| | import json |
| | import logging |
| | import os |
| | import asyncio |
| | import tempfile |
| | import time |
| | from typing import List, Dict, Optional, Any |
| | import openai |
| |
|
| | from core.config import settings |
| | from core.prompts import get_canvas_system_prompt, get_canvas_edit_prompt |
| | from services.s3_service import s3_service |
| |
|
| | logger = logging.getLogger(__name__) |
| |
|
| | class CanvasService: |
| | def __init__(self): |
| | self.openai_client = openai.OpenAI(api_key=settings.OPENAI_API_KEY) |
| |
|
| | async def generate_canvas_summary( |
| | self, |
| | file_key: Optional[str] = None, |
| | text_input: Optional[str] = None |
| | ) -> str: |
| | """ |
| | Generates a Markdown summary of the provided content. |
| | """ |
| | try: |
| | system_prompt = get_canvas_system_prompt() |
| | user_msg = "Please analyze the provided content and create a comprehensive, well-structured summary in Markdown format. Output ONLY the raw markdown content without code block markers." |
| |
|
| | if file_key: |
| | |
| | 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 |
| | ) |
| | |
| | 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}}, |
| | {"type": "text", "text": user_msg} |
| | ] |
| | } |
| | ] |
| | |
| | response = await asyncio.to_thread( |
| | self.openai_client.chat.completions.create, |
| | model="gpt-4o", |
| | messages=messages, |
| | temperature=0.7 |
| | ) |
| | |
| | await asyncio.to_thread(self.openai_client.files.delete, uploaded_file.id) |
| | return self._clean_markdown_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"{user_msg}\n\nCONTENT:\n{text_input}"} |
| | ] |
| | |
| | response = await asyncio.to_thread( |
| | self.openai_client.chat.completions.create, |
| | model="gpt-4o-mini", |
| | messages=messages, |
| | temperature=0.7 |
| | ) |
| | return self._clean_markdown_content(response.choices[0].message.content) |
| | |
| | else: |
| | raise ValueError("Either file_key or text_input must be provided") |
| |
|
| | except Exception as e: |
| | logger.error(f"Canvas summary generation failed: {e}") |
| | raise |
| |
|
| | async def refine_canvas( |
| | self, |
| | instruction: str, |
| | current_content: str |
| | ) -> str: |
| | """ |
| | Refines existing Markdown content based on user instructions. |
| | """ |
| | try: |
| | system_prompt = get_canvas_system_prompt() |
| | refine_prompt = get_canvas_edit_prompt(instruction, current_content) |
| | |
| | messages = [ |
| | {"role": "system", "content": system_prompt}, |
| | {"role": "user", "content": refine_prompt} |
| | ] |
| | |
| | response = await asyncio.to_thread( |
| | self.openai_client.chat.completions.create, |
| | model="gpt-4o", |
| | messages=messages, |
| | temperature=0.7 |
| | ) |
| | |
| | return self._clean_markdown_content(response.choices[0].message.content) |
| |
|
| | except Exception as e: |
| | logger.error(f"Canvas refinement failed: {e}") |
| | raise |
| |
|
| | def _clean_markdown_content(self, content: str) -> str: |
| | """Strips markdown code block markers (```markdown ... ```) if present.""" |
| | content = content.strip() |
| | if content.startswith("```"): |
| | |
| | content = content.split("\n", 1)[-1] if "\n" in content else content[3:] |
| | |
| | if content.endswith("```"): |
| | content = content[:-3] |
| | return content.strip() |
| |
|
| | canvas_service = CanvasService() |
| |
|