File size: 3,510 Bytes
71192d1
 
73a6a7e
 
 
 
71192d1
73a6a7e
71192d1
 
73a6a7e
 
 
 
 
 
ce2ce69
 
73a6a7e
71192d1
ce2ce69
 
71192d1
ce2ce69
73a6a7e
ce2ce69
73a6a7e
71192d1
ce2ce69
 
 
 
71192d1
73a6a7e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71192d1
73a6a7e
 
 
 
 
 
71192d1
73a6a7e
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import openai
import logging
import asyncio
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
from app.core.config import settings, APP_NAME
from app.core.exceptions import ServiceError

logger = logging.getLogger(f"{APP_NAME}.services.gpt4_rewrite")

class GPT4Rewriter:
    @retry(
        stop=stop_after_attempt(3),
        wait=wait_exponential(multiplier=1, min=2, max=10),
        retry=retry_if_exception_type(openai.APIError)
    )
    async def rewrite(self, text: str, user_api_key: str, instruction: str) -> dict:
        try:
            if not user_api_key:
                raise ServiceError(status_code=401, detail="OpenAI API key is missing. Please provide your key to use this feature.")

            text = text.strip()
            instruction = instruction.strip()

            if not text:
                raise ServiceError(status_code=400, detail="Input text is empty for rewriting.")
            if not instruction:
                raise ServiceError(status_code=400, detail="Rewrite instruction is missing.")

            messages = [
                {"role": "system", "content": instruction},
                {"role": "user", "content": text},
            ]

            def _call_openai_api():
                client = openai.OpenAI(api_key=user_api_key)
                response = client.chat.completions.create(
                    model=settings.OPENAI_MODEL,
                    messages=messages,
                    temperature=settings.OPENAI_TEMPERATURE,
                    max_tokens=settings.OPENAI_MAX_TOKENS
                )
                return response.choices[0].message.content.strip()

            result = await asyncio.to_thread(_call_openai_api)
            return {"rewritten_text": result}

        except openai.APIStatusError as e:
            logger.error(f"OpenAI API status error: {e.status_code} - {e.response}", exc_info=True)
            detail_message = "An OpenAI API error occurred."
            if e.status_code == 401:
                detail_message = "Invalid OpenAI API key. Please check your key."
            elif e.status_code == 429:
                detail_message = "OpenAI API rate limit exceeded or quota exhausted. Please try again later."
            elif e.status_code == 400:
                detail_message = f"OpenAI API request error: {e.response.json().get('detail', e.message)}"

            raise ServiceError(status_code=e.status_code, detail=detail_message) from e

        except openai.APITimeoutError as e:
            logger.error(f"OpenAI API timeout error: {e}", exc_info=True)
            raise ServiceError(status_code=504, detail="OpenAI API request timed out. Please try again.") from e

        except openai.APIConnectionError as e:
            logger.error(f"OpenAI API connection error: {e}", exc_info=True)
            raise ServiceError(status_code=503, detail="Could not connect to OpenAI API. Please check your internet connection.") from e

        except openai.APIError as e:
            logger.error(f"OpenAI API error: {e}", exc_info=True)
            raise ServiceError(status_code=500, detail=f"An unexpected OpenAI API error occurred: {str(e)}") from e

        except ServiceError as e:
            raise e

        except Exception as e:
            logger.error(f"Unexpected error in GPT-4 rewrite for text: '{text[:50]}...'", exc_info=True)
            raise ServiceError(status_code=500, detail="An unexpected error occurred during rewriting.") from e