File size: 5,037 Bytes
da6d052
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a766b1d
 
 
da6d052
 
a766b1d
da6d052
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a066775
da6d052
 
 
 
 
 
 
 
 
 
a570e87
da6d052
a570e87
da6d052
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os
import openai
import streamlit as st
from dotenv import load_dotenv
import boto3
import base64
import datetime
import json

load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
client = openai.OpenAI(api_key=OPENAI_API_KEY)

dynamodb = boto3.resource(
    'dynamodb',
    aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'), 
    aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY'),
    region_name='ap-northeast-2'  # ์›ํ•˜๋Š” ๋ฆฌ์ „์œผ๋กœ ๋ณ€๊ฒฝ
)
table = dynamodb.Table('ChatbotConversations')

original_allowed_usernames = os.getenv('ALLOWED_NAMES')
original_allowed_usernames = original_allowed_usernames.strip()

# JSON ํŒŒ์‹ฑ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
allowed_usernames = json.loads(original_allowed_usernames)


def is_valid_username(username):
    return username in allowed_usernames

st.title(':male-teacher: AI ROBLOX Tutor')
st.header(':one: Tutor: Ask questions for programming your own Roblox game!')

user_id = st.text_input(label='Assigned ID.')


if is_valid_username(user_id):
    st.write(f'ID: :violet[{user_id}]')
    query = st.text_input(
        label='Write your question.',
        placeholder='ex. What properties should I adjust to change the transparency of a Roblox Part?'
    )

    st.write(f'Query: :violet[{query}]')

    query_1 = 'AT_TUTOR_1: ' + query
    
    # ์ด๋ฏธ์ง€ ์ž…๋ ฅ
    image_uploaded1 = st.file_uploader("OPTIONAL: Upload an image", type=["png", "jpg", "jpeg"])

    def tutor_persona_query(query, image_data=None):
        import openai
        openai.api_key = OPENAI_API_KEY

        VISION_PROMPT_MESSAGES = [
            {
                "role": "system",
                "content": "Your role: You are an AI tutor providing interactive learning support for students engaged in constructionist gaming. Your goal is to offer personalized assistance that aligns with the learnerโ€™s objectives. Context: - The learner is building a game using [Roblox/Lua-based scripting]. - The learner is a pre-service teacher in a digital literacy course. - The learner is engaged in design-based, constructionist learning, working on ill-structured problems. - The learner may need help with computational thinking (CT) concepts such as decomposition, abstraction, algorithmic thinking, and pattern recognition. User Input: - The learner describes a challenge related to game design, programming logic, or debugging. - The learner may request alternative approaches, idea generation, or clarification of CT principles. Expected AI Response: 1. **Restate the learner's problem** in a concise and structured way to confirm understanding. 2. **Provide step-by-step guidance** for solving the problem (e.g., break it into subtasks, suggest a debugging strategy). 3. **Generate alternative approaches** if applicable. 4. **Explain relevant computational thinking concepts** (e.g., if the learner is struggling with loops, explain iteration and suggest a simplified example). 5. **Encourage self-reflection** by prompting the learner to apply the solution to their project. 6. If applicable, **provide a relevant external resource or documentation link**."
            },
            {"role": "user", "content": query},
        ]

        if image_data is not None:
            encoded_image = base64.b64encode(image_data).decode("utf-8")
            VISION_PROMPT_MESSAGES.append({"role": "user", "content": encoded_image})


        params = {
            "model": "gpt-4o-mini",
            "messages": VISION_PROMPT_MESSAGES,
            "max_tokens": 3000, # 1024,
        }

        trimmed_answer = ""  # trimmed_answer ์ดˆ๊ธฐํ™”
        try:
            full_answer = openai.chat.completions.create(**params)
            trimmed_answer = full_answer.choices[0].message.content
        except Exception as e:
            print(f"Error: {e}")
            trimmed_answer = f"Error: {e}"  # ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ trimmed_answer์— ํ• ๋‹น

        return trimmed_answer

    # ๋ฒ„ํŠผ ํด๋ฆญ
    button1 = st.button(':sparkles: ask :sparkles:')
    

    def save_message(user_id, message, timestamp=None):
        if timestamp is None:
            timestamp = datetime.datetime.now()

        # datetime ๊ฐ์ฒด๋ฅผ DynamoDB ์ง€์› ํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜
        if isinstance(timestamp, datetime.datetime):
            timestamp = int(timestamp.timestamp())  # Unix ํƒ€์ž„์Šคํƒฌํ”„(์ดˆ ๋‹จ์œ„ ์ •์ˆ˜)๋กœ ๋ณ€ํ™˜

        table.put_item(
            Item={
                'UserID': user_id,
                'Timestamp': timestamp,
                'Message': message
            }
        )


    if button1:
        query_1 = query_1
        save_message(user_id, query_1) 

        if image_uploaded1 is not None:
            image_data = image_uploaded1.read()
            answer = tutor_persona_query(query, image_data)
        else:
            answer = tutor_persona_query(query)
        
        answer_1 = 'AT_TUTOR_1: ' + answer
        save_message(user_id, answer_1)
        st.write(f'{answer}')
    

else:
    st.warning("Invalid username. Please enter a valid username.")