milestone done - added project descriptions, small changes
This commit is contained in:
parent
4b39fb96bb
commit
311ffc9849
@ -19,8 +19,7 @@ def get_client() -> OpenAI:
|
||||
client = get_client()
|
||||
|
||||
def send_message(message: str) -> str:
|
||||
# hier gehts darum, die message vorzubereiten
|
||||
# -> also nachricht aus den Chatfenster mit systemprompts und file_conntext verknüpfen
|
||||
# Nachricht aus dem Chatfenster wird für qwen vorbereitet und mit Kontext über SystemPrompter ergänzt
|
||||
prompt = generate_prompt(message)
|
||||
response = send_prompt(prompt)
|
||||
return response
|
||||
|
||||
@ -2,7 +2,7 @@ import streamlit as st
|
||||
import subprocess
|
||||
|
||||
def log_error(error_message):
|
||||
#speichern wieder über session_state
|
||||
#speichern des strukturierten outputs von qwen über session_state
|
||||
st.session_state["bugs"] = error_message
|
||||
|
||||
|
||||
@ -20,7 +20,6 @@ def format_debug_output(output: dict) -> str:
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
#qwen
|
||||
def format_output(text: bytes) -> str:
|
||||
return text.decode('utf-8', errors='replace').strip()
|
||||
|
||||
|
||||
@ -6,6 +6,8 @@ from DebugLogger import log_error, format_output, format_error
|
||||
|
||||
|
||||
def run_code(code: Path) -> None | str:
|
||||
#führt Code aus angeklickter Datei im Editor aus. Sicherheitscheck über verbotene Imports und Funktionen geregelt
|
||||
|
||||
if "code_output" in st.session_state:
|
||||
del st.session_state['code_output']
|
||||
if "code_error" in st.session_state:
|
||||
@ -29,20 +31,11 @@ def run_code(code: Path) -> None | str:
|
||||
st.session_state['code_error'] = format_error(exc)
|
||||
log_error(st.session_state['code_error'])
|
||||
|
||||
|
||||
#brauchts diese Funktion noch? macht eigentlich schon run_code
|
||||
def capture_output():
|
||||
errors = st.session_state['code_error']
|
||||
#if errors == 0:
|
||||
# errors = "There are no errors"
|
||||
return st.session_state['code_output'], errors
|
||||
|
||||
|
||||
|
||||
#aus der uebungsloesung
|
||||
|
||||
def check_code_safety(code: str) -> str | None:
|
||||
#Analysiert den Code statisch nach verbotenen imports und builtins.
|
||||
#analysiert den Code statisch nach verbotenen imports und builtins.
|
||||
try:
|
||||
tree = ast.parse(code)
|
||||
except SyntaxError as e:
|
||||
|
||||
@ -15,7 +15,7 @@ def read_file(file_path: Path) -> str:
|
||||
return file.read()
|
||||
|
||||
def save_file(file_path: Path, content: str):
|
||||
#wenn eine Datei im Code Editor abgeändert wird, soll die Funktion die Änderungen abspeichern
|
||||
#wenn eine Datei im Code Editor abgeändert wird und der Save Button gedrückt wurde, speichert Funktion die Änderungen ab
|
||||
with file_path.open('w') as file:
|
||||
file.write(content)
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from ddgs import DDGS
|
||||
import re
|
||||
|
||||
def perform_search(query: str) -> dict:
|
||||
#sucht Zusatzinfos im Internet
|
||||
try:
|
||||
results = DDGS().text(query, max_results=3)
|
||||
return results
|
||||
@ -12,7 +12,8 @@ def perform_search(query: str) -> dict:
|
||||
|
||||
|
||||
def parse_results(results: list[dict]) -> list[dict]:
|
||||
return [
|
||||
#Limitiert Inhalt der Suchergebnisse auf 500 Zeichen, damit qwen nicht zu langen Prompt erhält
|
||||
return [
|
||||
{
|
||||
"url": r.get("href", ""), #
|
||||
"snippet": r.get("body", "")[:500]
|
||||
|
||||
@ -3,7 +3,7 @@ from SearchManager import perform_search, parse_results
|
||||
|
||||
|
||||
def generate_prompt(user_message: str) -> str:
|
||||
|
||||
# der key "debug" im session_state als toggle: wenn an, dann strukturierter output mit feedbackschleife über "bugs" key
|
||||
if "debug" in st.session_state and st.session_state["debug"]:
|
||||
system_content = """\
|
||||
You are a code-review assistant. You ALWAYS respond with valid JSON and
|
||||
@ -37,10 +37,11 @@ commentary. Your entire response must be parseable by json.loads().
|
||||
context += (f" <bugs> {st.session_state['bugs']} </bugs>")
|
||||
|
||||
prompt = system_content + task + context
|
||||
#st.session_state["last_prompt"] = (f"{prompt}")
|
||||
st.session_state["last_prompt"] = (f"{prompt}")
|
||||
return prompt
|
||||
|
||||
|
||||
else:
|
||||
# ohne "debug" key im session_state: unstrukturierter output
|
||||
system_content = """\
|
||||
<persona>
|
||||
You are an experienced Python coding assistant.
|
||||
@ -68,7 +69,7 @@ commentary. Your entire response must be parseable by json.loads().
|
||||
|
||||
prompt = system_content + task + context
|
||||
|
||||
#st.session_state["last_prompt"] = (f"{prompt}")
|
||||
st.session_state["last_prompt"] = (f"{prompt}")
|
||||
|
||||
return prompt
|
||||
|
||||
|
||||
19
app.py
19
app.py
@ -3,28 +3,22 @@ import json
|
||||
import streamlit as st
|
||||
from pathlib import Path
|
||||
from ChatManager import send_message
|
||||
from FileManager import list_files, read_file, save_file, open_file
|
||||
from FileManager import list_files, save_file, open_file
|
||||
from ExecutionEngine import run_code
|
||||
from DebugLogger import format_debug_output, log_error
|
||||
|
||||
|
||||
#"Last sent prompt:",
|
||||
#if "last_prompt" in st.session_state:
|
||||
# st.session_state["last_prompt"]
|
||||
#if "file_content" in st.session_state:
|
||||
# st.session_state["file_content"]
|
||||
#type(st.session_state["file_content"])
|
||||
#print(type(st.session_state["file_content"]))
|
||||
|
||||
st.set_page_config(layout="wide")
|
||||
|
||||
# Initialisierung wichtiger keys im session_state
|
||||
if not "file_content" in st.session_state:
|
||||
st.session_state["file_content"] = ""
|
||||
if not "selected_file" in st.session_state:
|
||||
st.session_state["selected_file"] = ""
|
||||
|
||||
with st.sidebar:
|
||||
|
||||
# baut den Sidebar aus den vorhanden .py Dateien im Arbeitsverzeichnis
|
||||
for file in list_files():
|
||||
st.button(file.name, on_click=open_file, args=[file])
|
||||
|
||||
@ -35,7 +29,7 @@ with col_editor_output:
|
||||
if "file_content" in st.session_state:
|
||||
text = st.text_area("Code Editor", height="stretch", key="file_content")
|
||||
|
||||
# Preferred pattern for editor
|
||||
# Oberfläche erhält zusätzliche Buttons, wenn eine Datei geöffnet wird
|
||||
if st.session_state["selected_file"] != "":
|
||||
st.button("Save", on_click=save_file, args=[st.session_state["selected_file"], st.session_state["file_content"]])
|
||||
st.button("Execute Code", on_click=run_code, args=[st.session_state["selected_file"]])
|
||||
@ -55,13 +49,13 @@ with col_chat:
|
||||
if "messages" not in st.session_state:
|
||||
st.session_state.messages = []
|
||||
|
||||
# Display History
|
||||
# zeigt Chatverlauf als Abschnitt mit eigenem Scrollbalken
|
||||
with st.container(border=True, height=500):
|
||||
for msg in st.session_state.messages:
|
||||
with st.chat_message(msg["role"]):
|
||||
st.write(msg["content"])
|
||||
|
||||
# Input & Response
|
||||
# regelt Verhalten bei Chat mit qwen. Nach Eingabe wird einer der Promptopitionen gewählt und fertiger Prompt sowie qwen Antwort in die messages gespeichert
|
||||
message = st.chat_input("How can qwen help you?", key="chat")
|
||||
internet = st.toggle("enable internet search", key="internet")
|
||||
if "code_output" in st.session_state or "code_error" in st.session_state:
|
||||
@ -72,7 +66,6 @@ with col_chat:
|
||||
if "debug" in st.session_state and st.session_state["debug"]:
|
||||
response = format_debug_output(json.loads(response))
|
||||
log_error(response)
|
||||
# st.session_state["bugs"] = response
|
||||
st.session_state.messages.append({"role": "assistant", "content": response})
|
||||
st.rerun()
|
||||
|
||||
|
||||
135
project_description.md
Normal file
135
project_description.md
Normal file
@ -0,0 +1,135 @@
|
||||
**Lightweight Code Editor with AI integration**
|
||||
|
||||
##1. Introduction
|
||||
|
||||
This code editor was made as a project for the course Artificial Intelligence in Software Engineering I at FH Graubuenden.
|
||||
Its purpose is to help with coding questions and debugging.
|
||||
|
||||
|
||||
##2. Requirements
|
||||
|
||||
streamlit
|
||||
openai
|
||||
ddgs
|
||||
dotenv
|
||||
|
||||
##3. Installation
|
||||
|
||||
- install requirements through pip
|
||||
- aquire the environment variables thourgh FHGR
|
||||
- connect to the FHGR VPN to get access to the AI model.
|
||||
- run the app via terminal with "streamlit run app.py". A browser window will open.
|
||||
|
||||
##4. Architecture
|
||||
|
||||
The code is split up into frontend (app.py) and backend modules (FileManager, ChatManager, SystemPrompter, ExecutionEngine, DebugLogger and SearchManager).
|
||||
A lot of functionality is realized through the use of the session_state from streamlit.
|
||||
Since the streamlit app is rerun after each action the session_state is used to keep track of relevant information.
|
||||
|
||||
# 4.1 app.py
|
||||
|
||||
This module is the entrypoint for the streamlit functionality. It contains all elements that are visible when the program is run.
|
||||
|
||||
|
||||
- sidebar:
|
||||
The sidebar shows all python files within the working directory through fuctions found in the FileManager. Each file is represented by a clickable button.
|
||||
There is no functionality to add or delete files from within the program. To change the available files the user has to manually add them to the directory.
|
||||
Interacts with FileManger
|
||||
|
||||
- code editor:
|
||||
The code editor shows the contents of the opened file. The contents can be changed, saved and also executed.
|
||||
Interacts with FileManager, ExecutionEngine
|
||||
|
||||
- chat:
|
||||
This element consists of an input area to send messages to the AI, two toggles to enable different modes as well as a scrollable history.
|
||||
The first toggle is "enable internet search". This appends the results of an internet search to the prompt that is sent to the AI.
|
||||
This means the results from the search are not primarily for the user, but for the AI to use recent information before responing to the user.
|
||||
The second toggle "debug with qwen" appears only when a file was executed. This mode uses more structured output which is also sent to the next prompt for the AI.
|
||||
With this feedback the AI can help with a more focused approach to find and fix bugs in the code. The user has to implement the fixes themself since the AI cannot change the contents of the file.
|
||||
Interacts with ChatManager, Debuglogger
|
||||
|
||||
# 4.2 FileManager.py
|
||||
|
||||
This module manages the access to the working directory. It uses Path objects.
|
||||
The open_file function is only used as a helper function to save the file path and contents to the session_state.
|
||||
|
||||
# 4.3 ChatManager.py
|
||||
|
||||
The environment variables are located in a .env file which is excluded from the gitea upload.
|
||||
The qwen AI is accessed through the openai API client.
|
||||
While this module sends the messages to the AI it is heavily dependend on the SystemPrompter to supply the relevant context for the finished prompt.
|
||||
Interacts with SystemPrompter
|
||||
|
||||
# 4.4 SystemPrompter.py
|
||||
|
||||
This module handles all the context to add to the user message sent via the ChatManager. The instructions for the AI are structured with xml tags.
|
||||
There are two modes which are chosen with a toggle. Both modes differ in the system component and sent context.
|
||||
When the toggle is off the generated prompt includes system instructions which make the AI act as a coding assistant who gives short responses.
|
||||
With the toggle on the output is structured with json and focussed on finding bugs in the provided code. The AI's response is also loaded into the session_state.
|
||||
This means that subsequent messages to the AI keep its own responses therefore having the ability to iterate on them.
|
||||
Interacts with SearchManager
|
||||
|
||||
# 4.5 ExecutionEngine.py
|
||||
|
||||
With this module the program can execute the opened file after clicking the corresponding button in the streamlit app.
|
||||
There is a safety check before the subprocess is called to make sure no malicious actions can be made from within the program.
|
||||
Interacts with Debuglogger
|
||||
|
||||
# 4.6 DebugLogger.py
|
||||
|
||||
This module handles making all outputs from various other module more readable and useable.
|
||||
It saves the AI's response in the session_state to be able to send it with the next prompt when using the debug toggle.
|
||||
|
||||
# 4.7 SearchManager.py
|
||||
|
||||
This modules uses the duckduckgosearch API to make searching the internet possible.
|
||||
The user does not directly see the search, but the result is sent with the prompt to the AI.
|
||||
|
||||
|
||||
##5. Usage
|
||||
|
||||
The following examples illustrate how to use this program.
|
||||
|
||||
*I want to ask the AI about something in my file*
|
||||
**user actions**: - click on button with name of the file
|
||||
- write message to AI
|
||||
- wait for response
|
||||
- implement suggestions from AI
|
||||
|
||||
**interaction flow**: - st.sidebar uses list_files() to generate Buttons
|
||||
- on_click uses open_file() to load content and file Path into session_state
|
||||
- send_message() uses generate_prompt() to add system_prompt and context = file_content to the user_message
|
||||
- response is displayed by st.session_state.messages
|
||||
|
||||
|
||||
*I want to ask the AI about somehting in my file, but the AI has outdated info about the topic*
|
||||
**user actions**: - click on button with name of the file
|
||||
- activate "enable internet search" toggle
|
||||
- write message to AI
|
||||
- wait for response
|
||||
- implement suggestions from AI
|
||||
|
||||
**interaction flow**: - st.sidebar uses list_files() to generate Buttons
|
||||
- on_click uses open_file() to load content and file Path into session_state
|
||||
- send_message() uses generate_prompt() to add system_prompt and context = file_content and results from perform_search() to the user_message
|
||||
- response is displayed by st.session_state.messages
|
||||
|
||||
|
||||
*I want to debug my code*
|
||||
**user actions**: - click on button with name of the file
|
||||
- click the "execute code" button
|
||||
- write message to AI
|
||||
- wait for response
|
||||
- implement suggestions from AI
|
||||
- write message to AI
|
||||
- implement suggestions from AI
|
||||
|
||||
**interaction flow**: - st.sidebar uses list_files() to generate Buttons
|
||||
- on_click uses open_file() to load content and file Path into session_state
|
||||
- on_click uses run_code() to execute the file, results are formatted by format_output() or format_error()
|
||||
- code_output or code_error are loaded into seassion_state
|
||||
- send_message() uses generate_prompt() to add system_prompt which detects the "debug" toggle and adds context = file_content and code_output / code_error to the user_message
|
||||
- response is displayed by st.session_state.messages
|
||||
- send_message() uses generate_prompt() to add system_prompt which detects the "debug" toggle and adds context = file_content and code_output / code_error and debug response to the user_message
|
||||
- response is displayed by st.session_state.messages
|
||||
|
||||
BIN
~$praesentation_ai_se.pptx
Normal file
BIN
~$praesentation_ai_se.pptx
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user