File size: 5,588 Bytes
975967e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
"""Code explanation logic, independent of Gradio and of the Inference API.

The entry point is :func:`explain_code`, which owns the sequence: validate,
resolve the language, build the prompt, call the model, and return an
:class:`Explanation`. Rendering is ``app.py``'s job -- see
docs/adr/0002-coarse-entry-point-for-space-core-modules.md.

:func:`detect_language` and :func:`highlight_code` are public because the UI
needs them on their own: when explanation fails, the code pane is still shown
highlighted.
"""

from dataclasses import dataclass
from typing import Protocol

# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------
LANGUAGES = [
    "Auto-detect",
    "Python",
    "JavaScript",
    "TypeScript",
    "Java",
    "C++",
    "C",
    "Go",
    "Rust",
    "Ruby",
    "PHP",
    "Swift",
    "Kotlin",
    "SQL",
    "Bash",
    "HTML/CSS",
]

EXPLANATION_LEVELS = {
    "Beginner": "Explain this code in simple terms that a programming beginner would understand. Use analogies and avoid jargon. Focus on the 'what' rather than technical details.",
    "Intermediate": "Explain this code for someone with basic programming knowledge. Include technical details but explain any advanced concepts. Discuss both what the code does and how it works.",
    "Advanced": "Provide a thorough technical analysis of this code. Discuss implementation details, time/space complexity, potential edge cases, and possible improvements or alternatives.",
}


# Pygments' name for a language, where it differs from the label we show.
_LEXER_NAMES = {
    "JavaScript": "javascript",
    "TypeScript": "typescript",
    "C++": "cpp",
    "HTML/CSS": "html",
    "Bash": "bash",
}

AUTO_DETECT = "Auto-detect"
UNKNOWN = "Unknown"

MAX_TOKENS = 1500
TOP_P = 0.95
TEMPERATURE = 0.7


class InputError(ValueError):
    """The caller supplied no code to explain."""


class ChatFn(Protocol):
    """Send *messages* to a chat model and return its reply.

    Implementations may raise; :func:`explain_code` lets those propagate rather
    than substituting a plausible-looking explanation.
    """

    def __call__(
        self,
        messages: list[dict],
        *,
        max_tokens: int,
        temperature: float,
        top_p: float,
    ) -> str: ...


@dataclass(frozen=True)
class Explanation:
    """The result of explaining one snippet of code."""

    detected_language: str
    body: str
    highlighted_code: str


def detect_language(code: str) -> str:
    """Guess the language of *code*, or return ``"Unknown"``."""
    from pygments.lexers import guess_lexer

    try:
        return guess_lexer(code).name
    except Exception:  # noqa: BLE001 - pygments raises freely; Unknown is the fallback
        return UNKNOWN


def highlight_code(code: str, language: str) -> str:
    """Return *code* as syntax-highlighted HTML.

    Falls back to escaped plain text: highlighting is decoration, and failing to
    decorate must not cost the user sight of their own code.
    """
    import html

    from pygments import highlight
    from pygments.formatters import HtmlFormatter
    from pygments.lexers import get_lexer_by_name, guess_lexer

    try:
        if language in (AUTO_DETECT, UNKNOWN):
            lexer = guess_lexer(code)
        else:
            lexer = get_lexer_by_name(_LEXER_NAMES.get(language, language.lower()))
        return highlight(code, lexer, HtmlFormatter(style="monokai", noclasses=True))
    except Exception:  # noqa: BLE001 - decoration only; show the code regardless
        return f"<pre><code>{html.escape(code)}</code></pre>"


def _build_user_prompt(code: str, language: str) -> str:
    lexer_hint = language.split()[0].lower() if language.strip() else ""
    return f"""Explain the following code.

```{lexer_hint}
{code}
```

Provide a structured explanation with the following sections:

## Overview
A brief summary of what this code does (2-3 sentences).

## Step-by-Step Breakdown
Explain the code section by section, describing what each part does.

## Key Concepts
List and briefly explain the important programming concepts used in this code.

## Potential Improvements
Suggest any improvements, best practices, or potential issues to be aware of.

Keep your explanation clear, accurate, and educational."""


def explain_code(
    code: str,
    language: str,
    level: str,
    *,
    chat_fn: ChatFn,
) -> Explanation:
    """Explain *code* at the requested *level*.

    An unrecognised *level* falls back to Intermediate rather than failing: the
    value comes from a dropdown, so a bad one means a UI change, not bad input.

    Raises:
        InputError: *code* is empty or whitespace.
        Exception: whatever *chat_fn* raises.
    """
    if not code.strip():
        raise InputError("Please paste some code to explain.")

    resolved = detect_language(code) if language == AUTO_DETECT else language
    instruction = EXPLANATION_LEVELS.get(level, EXPLANATION_LEVELS["Intermediate"])

    body = chat_fn(
        [
            {
                "role": "system",
                "content": f"You are an expert programming tutor. {instruction}",
            },
            {"role": "user", "content": _build_user_prompt(code, resolved)},
        ],
        max_tokens=MAX_TOKENS,
        temperature=TEMPERATURE,
        top_p=TOP_P,
    )

    return Explanation(
        detected_language=resolved,
        body=body.strip(),
        highlighted_code=highlight_code(code, resolved),
    )