matsuap's picture
Upload folder using huggingface_hub
951d5c6 verified
import json
import logging
import os
import asyncio
import tempfile
from typing import List, Dict, Optional, Any
import openai
from core.config import settings
from core.prompts import get_report_prompt, get_report_suggestion_prompt
from services.s3_service import s3_service
logger = logging.getLogger(__name__)
class ReportService:
def __init__(self):
self.openai_client = openai.OpenAI(api_key=settings.OPENAI_API_KEY)
async def generate_format_suggestions(
self,
file_key: Optional[str] = None,
text_input: Optional[str] = None,
language: str = "Japanese"
) -> List[Dict[str, str]]:
"""
Generates 4 AI-suggested report formats based on the content.
Uses asyncio.to_thread for all blocking I/O operations.
"""
try:
system_prompt = get_report_suggestion_prompt(language)
if file_key:
# Download PDF from S3 (non-blocking)
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf")
tmp_path = tmp.name
tmp.close()
try:
await asyncio.to_thread(
s3_service.s3_client.download_file,
settings.AWS_S3_BUCKET,
file_key,
tmp_path
)
# Upload to OpenAI (non-blocking)
def upload_to_openai():
with open(tmp_path, "rb") as f:
return self.openai_client.files.create(
file=f,
purpose="assistants"
)
uploaded_file = await asyncio.to_thread(upload_to_openai)
messages = [
{"role": "system", "content": system_prompt},
{
"role": "user",
"content": [
{
"type": "file",
"file": {"file_id": uploaded_file.id}
}
]
}
]
# Call OpenAI (non-blocking)
response = await asyncio.to_thread(
self.openai_client.chat.completions.create,
model="gpt-4o-mini",
messages=messages,
response_format={"type": "json_object"},
temperature=0.7
)
# Clean up OpenAI file (non-blocking)
await asyncio.to_thread(
self.openai_client.files.delete,
uploaded_file.id
)
raw_content = response.choices[0].message.content
finally:
if os.path.exists(tmp_path):
await asyncio.to_thread(os.remove, tmp_path)
elif text_input:
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"Analyze this content:\n\n{text_input}"}
]
# Call OpenAI (non-blocking)
response = await asyncio.to_thread(
self.openai_client.chat.completions.create,
model="gpt-4o-mini",
messages=messages,
response_format={"type": "json_object"},
temperature=0.7
)
raw_content = response.choices[0].message.content
else:
raise ValueError("Either file_key or text_input must be provided")
data = json.loads(raw_content)
return data.get("suggestions", [])
except Exception as e:
logger.error(f"Format suggestion failed: {e}")
return []
async def generate_report(
self,
file_key: Optional[str] = None,
text_input: Optional[str] = None,
format_key: str = "briefing_doc",
custom_prompt: Optional[str] = None,
language: str = "Japanese"
) -> str:
"""
Generates a full report based on the selected format.
Uses asyncio.to_thread for all blocking I/O operations.
"""
try:
base_prompt = get_report_prompt(format_key, custom_prompt or "", language)
# Language styling instruction
if language == "Japanese":
system_prompt = (
"あなたは日本語でレポートを作成するAIアシスタントです。すべての回答は日本語で書いてください。\n\n"
f"{base_prompt}\n\n"
"重要: レポート全体を日本語で書いてください。回答はマークダウン形式で、適切な見出し、箇跨書き、構造を使用して読みやすくフォーマットしてください。"
)
else:
system_prompt = (
"You are an AI assistant that creates reports in English. Write all responses in English.\n\n"
f"{base_prompt}\n\n"
"IMPORTANT: Write the entire report in English. Please format your response in markdown with proper headings, bullet points, and structure for easy reading."
)
if file_key:
# Download PDF from S3 (non-blocking)
tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".pdf")
tmp_path = tmp.name
tmp.close()
try:
await asyncio.to_thread(
s3_service.s3_client.download_file,
settings.AWS_S3_BUCKET,
file_key,
tmp_path
)
# Upload to OpenAI (non-blocking)
def upload_to_openai():
with open(tmp_path, "rb") as f:
return self.openai_client.files.create(
file=f,
purpose="assistants"
)
uploaded_file = await asyncio.to_thread(upload_to_openai)
messages = [
{"role": "system", "content": system_prompt},
{
"role": "user",
"content": [
{
"type": "file",
"file": {"file_id": uploaded_file.id}
}
]
}
]
# Call OpenAI (non-blocking)
response = await asyncio.to_thread(
self.openai_client.chat.completions.create,
model="gpt-4o-mini",
messages=messages,
temperature=0.7
)
# Clean up OpenAI (non-blocking)
await asyncio.to_thread(
self.openai_client.files.delete,
uploaded_file.id
)
return response.choices[0].message.content
finally:
if os.path.exists(tmp_path):
await asyncio.to_thread(os.remove, tmp_path)
elif text_input:
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"Please analyze the following content and generate a report based on it:\n\n{text_input}"}
]
# Call OpenAI (non-blocking)
response = await asyncio.to_thread(
self.openai_client.chat.completions.create,
model="gpt-4o-mini",
messages=messages,
temperature=0.7
)
return response.choices[0].message.content
else:
raise ValueError("Either file_key or text_input must be provided")
except Exception as e:
logger.error(f"Report generation failed: {e}")
raise
report_service = ReportService()