File size: 4,157 Bytes
8506218
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9f5fa52
 
 
 
 
 
 
 
 
 
 
 
 
8506218
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from groq import Groq
import requests
import nbformat

# Initialize the Groq client
GROQ_API_KEY = "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"
client = Groq(api_key=GROQ_API_KEY)


def extract_file_id(google_drive_link):
    if "id=" in google_drive_link:
        return google_drive_link.split("id=")[-1]
    elif "drive.google.com/file/d/" in google_drive_link:
        return google_drive_link.split("file/d/")[-1].split("/")[0]
    else:
        raise ValueError("Invalid Google Drive link.")


def download_public_notebook(file_id):
    download_url = f"https://drive.google.com/uc?export=download&id={file_id}"
    response = requests.get(download_url)
    response.raise_for_status()
    return response.text


def parse_notebook_with_markdown(notebook_content):
    """
    Parse the notebook to extract markdown, code, and corresponding outputs.
    Markdown cells preceding a code cell are associated with it.
    """
    notebook = nbformat.reads(notebook_content, as_version=4)
    cells = notebook.cells

    parsed_cells = []
    current_markdown = ""

    for cell in cells:
        if cell.cell_type == "markdown":
            current_markdown += cell.source + "\n\n"  # Append markdown content
        elif cell.cell_type == "code":
            code = cell.source
            output = (
                "".join(
                    output.text for output in cell.outputs if hasattr(output, "text")
                )
                or "No output"
            )
            parsed_cells.append((current_markdown.strip(), code, output))
            current_markdown = (
                ""  # Reset markdown context after associating it with a code cell
            )

    return parsed_cells


def send_to_groq_api_with_context(markdown, code, output, cell_index):
    """
    Sends markdown, code, and output to the Groq API for grading.
    """
    prompt = f"""
    You are a Python notebook grader. Below is the context or question from a Jupyter notebook, followed by the corresponding Python code and its output.

    Your task is to:
    1. Grade the cell on a scale of 1 to 10 based on correctness, readability, and efficiency.
    2. Assess how well the code addresses the provided context or question.
    3. Identify any logical errors or flaws that would prevent the code from achieving its intended result, even if it runs without errors.
    4. Provide actionable suggestions for improvement, focusing on:
    - Code readability, modularity, and adherence to Pythonic practices.
    - Computational efficiency and possible optimizations.
    - Improvements in the clarity of the output and whether it aligns with the context.
    5. Identify areas for improvement and suggest alternative solutions if applicable.
    6. Avoid generating additional code unless it helps in demonstrating a recommended improvement.

    Cell Index: {cell_index}

    Context or Question:
    {markdown if markdown else "No specific context provided."}

    Code:
    {code}

    Output:
    {output}
    """

    chat_completion = client.chat.completions.create(
        messages=[
            {
                "role": "system",
                "content": "You are a Python notebook grader focusing on the provided context, code, and output for each cell. Provide a detailed analysis based on the following criteria, including checking for any logical errors that might affect the correctness of the code.",
            },
            {"role": "user", "content": prompt},
        ],
        model="llama3-8b-8192",
        temperature=0.5,
        max_tokens=1500,
        top_p=1,
    )

    return chat_completion.choices[0].message.content


def review_notebook_content(notebook_content):
    """
    Reviews a notebook's content and returns detailed feedback for each cell.
    """
    parsed_cells = parse_notebook_with_markdown(notebook_content)
    feedback_list = []

    for i, (markdown, code, output) in enumerate(parsed_cells, start=1):
        feedback = send_to_groq_api_with_context(markdown, code, output, i)
        feedback_list.append(f"Feedback for Cell {i}:\n{feedback}\n{'-' * 50}")

    return feedback_list