initial version

This commit is contained in:
Khanh Dinh 2024-12-30 23:15:03 +01:00
commit bc2e200a2b
19 changed files with 1001 additions and 0 deletions

1
.env Normal file
View File

@ -0,0 +1 @@
OPENAI_API_KEY=GTpNepFFXK6Gy3nHC9LiRteAJzkL4g67dn5CKD3a

5
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,5 @@
__pycache__/
*.pyc
.vscode/
.env
venv/

10
.idea/OKR_Proposer.iml generated Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

4
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (OKR_Proposer)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/OKR_Proposer.iml" filepath="$PROJECT_DIR$/.idea/OKR_Proposer.iml" />
</modules>
</component>
</project>

69
.idea/workspace.xml generated Normal file
View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="318c72a5-e9ec-4dd0-ac1a-cb0b5e2a86c2" name="Changes" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Python Script" />
</list>
</option>
</component>
<component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="ProjectId" id="2qwhdtwwl3dnedx4FlvRdDYZobj" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="$PROJECT_DIR$" />
</key>
</component>
<component name="RunManager">
<configuration name="main" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
<module name="OKR_Proposer" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="318c72a5-e9ec-4dd0-ac1a-cb0b5e2a86c2" name="Changes" comment="" />
<created>1735579636156</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1735579636156</updated>
</task>
<servers />
</component>
</project>

7
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": []
}

39
api.py Normal file
View File

@ -0,0 +1,39 @@
import requests
import os
import streamlit as st
from dotenv import load_dotenv
from settings import load_settings
from utils import construct_prompt
# Load API key from .env file
load_dotenv()
api_key = os.getenv("OPENAI_API_KEY")
if not api_key:
st.error("API key not found. Please set OPENAI_API_KEY in your .env file.")
st.stop()
api_url = "https://genai.dev.odp.lhgroup.de/openai/deployments/gpt-4-turbo/chat/completions?api-version=2023-07-01-preview"
def fetch_okrs(user_input: str):
settings = load_settings()
system_prompt = settings["system_prompt"]
input_template = settings["input_template"]
user_prompt = construct_prompt(prompt_template=input_template, user_input=user_input)
headers = {"api-key": api_key, "Content-Type": "application/json"}
body = {
"messages": [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
}
try:
response = requests.post(url=api_url, headers=headers, json=body)
response.raise_for_status()
return response.json()
except Exception as e:
st.error(f"Error fetching data from API: {e}")
return None

135
app.py Normal file
View File

@ -0,0 +1,135 @@
import streamlit as st
import os
import requests
import json
from styles import apply_styles
from streamlit_option_menu import option_menu
# Import other pages or modules
from settings import settings_page, load_settings
from proposer import proposer_page
apply_styles()
#proposer_page()
# Navigation Menu
selected = option_menu(
menu_title="Main Menu",
options=["Home", "Settings"],
icons=["house", "gear"],
menu_icon="cast",
default_index=0,
orientation="horizontal",
)
# Render pages based on selection
if selected == "Home":
# Home page logic goes here (e.g., OKR generator)
#from utils import construct_prompt # Example import; replace with actual logic.
proposer_page()
elif selected == "Settings":
settings_page()
'''
# Streamlit App Layout
st.title("OKR Generator")
# Input Section and Buttons Row
st.subheader("Enter your idea or goal:")
user_input = st.text_area(
"Input your idea here:",
value=st.session_state.get("user_input", INPUT_TEMPLATE.strip()),
height=200,
)
col1, col2 = st.columns([1, 1])
with col1:
if st.button("Reset All"):
st.session_state.clear()
with col2:
generate_okrs_clicked = st.button("Generate OKRs")
if generate_okrs_clicked:
if not user_input.strip():
st.warning("Please provide some input before generating OKRs.")
else:
with st.spinner("Generating OKRs..."):
# Construct prompt and call API
prompt = construct_prompt(prompt_template=PROMPT_TEMPLATE, user_input=user_input)
response = fetch_okrs(user_prompt=prompt, system_prompt=SYSTEM_PROMPT)
if response:
# Extract Objective and Key Results from response
objective, key_results = extract_llm_response(response)
st.session_state["objective"] = objective
st.session_state["key_results"] = key_results
# Display Results Only if an OKR Has Been Generated
if "objective" in st.session_state and "key_results" in st.session_state:
# Display Objective Field with Responsibles Input Below It
st.subheader("Proposal Objective:")
objective_text = st.text_area(
"Proposal Objective:",
value=st.session_state.get("objective", ""),
height=100,
)
responsible_for_objective = st.text_input(
"Responsibles for Objective (comma-separated):",
value="",
placeholder="e.g., Khanh Dinh, John Doe",
key="responsibles_objective"
)
# Display Key Results with Responsibles Below Each One
st.subheader("Proposal Key Results:")
key_result_boxes = []
responsibles_for_key_results = []
for i, kr in enumerate(st.session_state["key_results"], start=1):
kr_text = st.text_area(f"Key Result {i}:", value=kr, key=f"kr_{i}")
responsible_for_kr = st.text_input(
f"Responsibles for Key Result {i} (comma-separated):",
value="",
placeholder="e.g., Khanh Dinh",
key=f"responsibles_kr_{i}"
)
key_result_boxes.append(kr_text)
responsibles_for_key_results.append(responsible_for_kr)
# Finalize Button Center-Aligned
#finalize_col = st.columns([3, 2, 3])[1]
#with finalize_col:
if st.button("Finalize"):
finalized_objective = objective_text.strip()
finalized_key_results = [st.session_state[f"kr_{i+1}"].strip() for i in range(len(key_result_boxes))]
# Append initials of responsibles to Objective and Key Results
responsibles_list_objective = [name.strip() for name in responsible_for_objective.split(",") if name.strip()]
initials_objective = [f"[{''.join([part[0] for part in name.split()]).upper()}]" for name in responsibles_list_objective]
initials_str_objective = ", ".join(initials_objective)
finalized_objective += f" [{initials_str_objective}]"
finalized_key_results_with_initials = []
for i, kr in enumerate(finalized_key_results):
responsibles_list_kr = [name.strip() for name in responsibles_for_key_results[i].split(",") if name.strip()]
initials_kr = [f"{''.join([part[0] for part in name.split()]).upper()}" for name in responsibles_list_kr]
initials_str_kr = ", ".join(initials_kr)
finalized_key_results_with_initials.append(f"KR{i+1}: [{initials_str_kr}] {kr}")
# Display finalized data in non-editable format (full width)
st.subheader("Finalized Objective:")
st.write(finalized_objective)
st.subheader("Finalized Key Results:")
for kr in finalized_key_results_with_initials:
st.write(kr)'''

58
config.py Normal file
View File

@ -0,0 +1,58 @@
SYSTEM_PROMPT = """
You are an OKR coach and support us, as beginners in OKRs, with the correct phrasing of OKRs.
Always one proposal and provide the proposal in the requested format (json).
If you think the input is not clear enough and the OKR could be improved, then provide a hint,
what could be added to the user input in order to provide improved OKRs. The hint should also
always provided within the json.
Format could look like this:
{
"hint": "any additional questions, which can be added to the user input to rerun the prompting",
"proposals": [
{
"objective":"objective variant 1",
"key_results": ["key result 1"]
},
...
]
}
"""
INPUT_TEMPLATE = """
We want to improve our SLA framework by finalizing the current SLA template, which is used for the negotiations with our ground service partners.
The resulting SLA will be used in order to measure the quality of the service partner and issue penalties if targets are not met.
We would like to improve this, to have a better steering function, e.g. by adding a bonus component to the SLA framework.
To achieve this, we need to develop a bonus concept which is viable, feasible and desirable.
We need to simulate the concept, so that we don't risk issuing too much bonus which we cannot cover.
We need to define organizational processes and responsibilities so that we are able to pay a bonus.
How should the OKR look like for the next cycle which starts in Jan 2025 and ends in Apr 2025?
"""
# Prompt template for user input
PROMPT_TEMPLATE = """
Please help us in defining proper OKRs.
Here is what we have thought about and we would like to phrase an OKR with up to 5 key results.
this is the user input:
{user_input}
Please provide the response in json format.
the three proposals and potentially further questions to the user to improve the OKR, should be structured in a json as response.
Objective (key: objective)
key results (list with the key results)
The json could be structured like this:
{
"hint": "any additional questions, which can be added to the user input to rerun the prompting",
"proposals": [
{
"objective":"objective variant 1",
"key_result_1":"key result 1",
...
},
...
]
}
"""

42
main.py Normal file
View File

@ -0,0 +1,42 @@
import streamlit as st
from dotenv import load_dotenv
from api import fetch_okrs
from utils import construct_prompt, extract_llm_response
from styles import apply_styles
from config import SYSTEM_PROMPT, INPUT_TEMPLATE
# Load environment variables
load_dotenv()
# Apply custom styles
apply_styles()
# Streamlit App Layout
st.title("OKR Generator")
st.subheader("Enter your idea or goal:")
user_input = st.text_area(
"Input your idea here:",
value=st.session_state.get("user_input", INPUT_TEMPLATE.strip()),
height=200,
)
if st.button("Generate OKRs"):
if not user_input.strip():
st.warning("Please provide some input before generating OKRs.")
else:
with st.spinner("Generating OKRs..."):
prompt = construct_prompt(user_input)
response = fetch_okrs(prompt=prompt, system_prompt=SYSTEM_PROMPT)
if response:
objective, key_results = extract_llm_response(response)
st.session_state["objective"] = objective
st.session_state["key_results"] = key_results
if "objective" in st.session_state:
st.subheader("Proposal Objective:")
st.write(st.session_state["objective"])
st.subheader("Proposal Key Results:")
for kr in st.session_state["key_results"]:
st.write(kr)

116
proposer.py Normal file
View File

@ -0,0 +1,116 @@
import streamlit as st
from api import fetch_okrs
from config import SYSTEM_PROMPT, INPUT_TEMPLATE, PROMPT_TEMPLATE
from utils import construct_prompt, extract_llm_response
def proposer_page():
# Streamlit App Layout
st.title("OKR Generator")
# Input Section and Buttons Row
st.subheader("Enter your idea or goal:")
user_input = st.text_area(
"Input your idea here:",
value=st.session_state.get("user_input", INPUT_TEMPLATE.strip()),
height=200,
)
col1, col2 = st.columns([1, 1])
with col1:
if st.button("Reset All"):
st.session_state.clear()
with col2:
generate_okrs_clicked = st.button("Generate OKRs")
if generate_okrs_clicked:
if not user_input.strip():
st.warning("Please provide some input before generating OKRs.")
else:
with st.spinner("Generating OKRs..."):
# Construct prompt and call API
#prompt = construct_prompt(prompt_template=PROMPT_TEMPLATE, user_input=user_input)
response = fetch_okrs(user_input=user_input)
if response:
# Extract Objective and Key Results from response
print(response)
objective, key_results, hint = extract_llm_response(response)
st.session_state["objective"] = objective
st.session_state["key_results"] = key_results
st.session_state["hint"] = hint
#st.subheader("Hint to improve the OKR proposal")
#st.text(hint)
# Display Results Only if an OKR Has Been Generated
if "objective" in st.session_state and "key_results" in st.session_state:
# Display Objective Field with Responsibles Input Below It
st.subheader("Proposal Objective:")
objective_text = st.text_area(
"Proposal Objective:",
value=st.session_state.get("objective", ""),
height=100,
)
responsible_for_objective = st.text_input(
"Responsibles for Objective (comma-separated):",
value="",
placeholder="e.g., Khanh Dinh, John Doe",
key="responsibles_objective"
)
# Display Key Results with Responsibles Below Each One
st.subheader("Proposal Key Results:")
key_result_boxes = []
responsibles_for_key_results = []
for i, kr in enumerate(st.session_state["key_results"], start=1):
kr_text = st.text_area(f"Key Result {i}:", value=kr, key=f"kr_{i}")
responsible_for_kr = st.text_input(
f"Responsibles for Key Result {i} (comma-separated):",
value="",
placeholder="e.g., Khanh Dinh",
key=f"responsibles_kr_{i}"
)
key_result_boxes.append(kr_text)
responsibles_for_key_results.append(responsible_for_kr)
# Finalize Button Center-Aligned
#finalize_col = st.columns([3, 2, 3])[1]
#with finalize_col:
if st.button("Finalize"):
finalized_objective = objective_text.strip()
finalized_key_results = [st.session_state[f"kr_{i+1}"].strip() for i in range(len(key_result_boxes))]
# Append initials of responsibles to Objective and Key Results
responsibles_list_objective = [name.strip() for name in responsible_for_objective.split(",") if name.strip()]
initials_objective = [f"[{''.join([part[0] for part in name.split()]).upper()}]" for name in responsibles_list_objective]
initials_str_objective = ", ".join(initials_objective)
finalized_objective = f"{initials_str_objective} {finalized_objective}"
finalized_key_results_with_initials = []
for i, kr in enumerate(finalized_key_results):
responsibles_list_kr = [name.strip() for name in responsibles_for_key_results[i].split(",") if name.strip()]
initials_kr = [f"{''.join([part[0] for part in name.split()]).upper()}" for name in responsibles_list_kr]
initials_str_kr = ", ".join(initials_kr)
finalized_key_results_with_initials.append(f"KR{i+1}: [{initials_str_kr}] {kr}")
# Display finalized data in non-editable format (full width)
st.subheader("Finalized Objective:")
st.code(
body=finalized_objective,
language=None,
wrap_lines=True
)
st.subheader("Finalized Key Results:")
for kr in finalized_key_results_with_initials:
st.code(
body=kr,
language=None,
wrap_lines=True
)

74
requirements.txt Normal file
View File

@ -0,0 +1,74 @@
altair==5.5.0
appnope==0.1.4
asttokens==3.0.0
attrs==24.3.0
blinker==1.9.0
cachetools==5.5.0
certifi==2024.12.14
charset-normalizer==3.4.1
click==8.1.8
comm==0.2.2
cramjam==2.9.1
debugpy==1.8.11
decorator==5.1.1
et-xmlfile==2.0.0
exceptiongroup==1.2.2
executing==2.1.0
fastparquet==2024.11.0
fsspec==2024.12.0
gitdb==4.0.11
GitPython==3.1.43
idna==3.10
importlib-metadata==8.5.0
ipykernel==6.29.5
ipython==8.18.1
jedi==0.19.2
jinja2==3.1.5
jsonschema==4.23.0
jsonschema-specifications==2024.10.1
jupyter-client==8.6.3
jupyter-core==5.7.2
markdown-it-py==3.0.0
MarkupSafe==3.0.2
matplotlib-inline==0.1.7
mdurl==0.1.2
narwhals==1.20.1
nest-asyncio==1.6.0
numpy==2.0.2
openpyxl==3.1.5
packaging==24.2
pandas==2.2.3
parso==0.8.4
pexpect==4.9.0
pillow==11.0.0
platformdirs==4.3.6
prompt-toolkit==3.0.48
protobuf==5.29.2
psutil==6.1.1
ptyprocess==0.7.0
pure-eval==0.2.3
pyarrow==18.1.0
pydeck==0.9.1
pygments==2.18.0
pypdf2==3.0.1
python-dateutil==2.9.0.post0
python-dotenv==1.0.1
pytz==2024.2
pyzmq==26.2.0
referencing==0.35.1
requests==2.32.3
rich==13.9.4
rpds-py==0.22.3
six==1.17.0
smmap==5.0.1
stack-data==0.6.3
streamlit==1.41.1
tenacity==9.0.0
toml==0.10.2
tornado==6.4.2
traitlets==5.14.3
typing-extensions==4.12.2
tzdata==2024.2
urllib3==2.3.0
wcwidth==0.2.13
zipp==3.21.0

202
settings.py Normal file
View File

@ -0,0 +1,202 @@
import streamlit as st
import json
import os
from config import SYSTEM_PROMPT, INPUT_TEMPLATE, PROMPT_TEMPLATE
def settings_page():
st.title("Settings")
# Section for System Prompt
st.subheader("System Prompt")
if "system_prompt" not in st.session_state:
st.session_state["system_prompt"] = SYSTEM_PROMPT.strip()
system_prompt = st.text_area(
"Define the system prompt:",
value=st.session_state["system_prompt"]
)
# Section for Input Template
st.subheader("Input Template")
if "input_template" not in st.session_state:
st.session_state["input_template"] = INPUT_TEMPLATE.strip()
input_template = st.text_area(
"Define the input template:",
value=st.session_state["input_template"],
height=400
)
# Section for Prompt Template
st.subheader("Prompt Template")
if "prompt_template" not in st.session_state:
st.session_state["prompt_template"] = PROMPT_TEMPLATE.strip()
prompt_template = st.text_area(
"Define the prompt template:",
value=st.session_state["prompt_template"]
)
# Section for Number of Key Results
st.subheader("Number of Key Results")
if "num_key_results" not in st.session_state:
st.session_state["num_key_results"] = 4
num_key_results = st.number_input(
"Set the maximum number of key results:",
min_value=1,
max_value=10,
value=st.session_state["num_key_results"]
)
# Save Button for Settings
if st.button("Save Settings"):
st.session_state["system_prompt"] = system_prompt
st.session_state["input_template"] = input_template
st.session_state["prompt_template"] = prompt_template
st.session_state["num_key_results"] = num_key_results
st.success("Settings saved successfully!")
# Section for Team Member Management
team_member_management()
def team_member_management():
st.subheader("Team Member Management")
# Initialize team members in session state
if "team_members" not in st.session_state:
st.session_state["team_members"] = ["John Doe", "Jane Smith"]
# Display current team members
st.write("### Current Team Members")
for member in st.session_state["team_members"]:
col1, col2 = st.columns([4, 1])
col1.write(member)
if col2.button("Remove", key=f"remove_{member}"):
st.session_state["team_members"].remove(member)
st.experimental_rerun()
# Add new team member
st.write("### Add New Team Member")
new_member = st.text_input("Enter new team member name:", key="new_member")
if st.button("Add Team Member"):
if new_member.strip():
if new_member.strip() not in st.session_state["team_members"]:
st.session_state["team_members"].append(new_member.strip())
st.success(f"Added {new_member.strip()} to the team.")
st.experimental_rerun()
else:
st.warning(f"{new_member.strip()} is already in the team.")
else:
st.warning("Please enter a valid name.")
SETTINGS_FILE = "settings.json"
# Load settings from JSON file
def load_settings():
if os.path.exists(SETTINGS_FILE) and 1 == 2:
with open(SETTINGS_FILE, "r") as f:
return json.load(f)
else:
# Default settings
return {
"system_prompt": SYSTEM_PROMPT,
"input_template": INPUT_TEMPLATE,
"prompt_template": PROMPT_TEMPLATE,
"num_key_results": 4,
"team_members": ["Khanh Dinh", "Robin Plitzko", "Roberto Renna"],
"team_member_template": "{name} - Team Member"
}
# Save settings to JSON file
def save_settings(settings):
with open(SETTINGS_FILE, "w") as f:
json.dump(settings, f, indent=4)
# Settings Page
def settings_page():
st.title("Settings")
# Load settings
settings = load_settings()
# Section for System Prompt
st.subheader("System Prompt")
system_prompt = st.text_area(
"Define the system prompt:",
value=settings["system_prompt"]
)
# Section for Input Template
st.subheader("Input Template")
input_template = st.text_area(
"Define the input template:",
value=settings["input_template"]
)
# Section for Prompt Template
st.subheader("Prompt Template")
prompt_template = st.text_area(
"Define the prompt template (use {num_key_results} for dynamic insertion):",
value=settings["prompt_template"]
)
# Section for Number of Key Results
st.subheader("Number of Key Results")
num_key_results = st.number_input(
"Set the maximum number of key results:",
min_value=1,
max_value=10,
value=settings["num_key_results"]
)
# Section for Team Member Template
st.subheader("Team Member Template")
team_member_template = st.text_input(
"Define a template for team members (use {name} for dynamic insertion):",
value=settings["team_member_template"]
)
# Section for Team Member Management
team_member_management(settings)
# Save Button for Settings
if st.button("Save Settings"):
# Update settings dictionary
settings["system_prompt"] = system_prompt
settings["input_template"] = input_template
settings["prompt_template"] = prompt_template
settings["num_key_results"] = num_key_results
settings["team_member_template"] = team_member_template
# Save to file
save_settings(settings)
st.success("Settings saved successfully!")
# Team Member Management Section
def team_member_management(settings):
st.subheader("Team Member Management")
# Display current team members
st.write("### Current Team Members")
for member in settings["team_members"]:
col1, col2 = st.columns([4, 1])
col1.write(member)
if col2.button(f"Remove {member}", key=f"remove_{member}"):
settings["team_members"].remove(member)
save_settings(settings)
st.experimental_rerun()
# Add new team member
st.write("### Add New Team Member")
new_member = st.text_input("Enter new team member name:", key="new_member")
if st.button("Add Team Member"):
if new_member.strip():
if new_member.strip() not in settings["team_members"]:
settings["team_members"].append(new_member.strip())
save_settings(settings)
st.success(f"Added {new_member.strip()} to the team.")
st.experimental_rerun()
else:
st.warning(f"{new_member.strip()} is already in the team.")
else:
st.warning("Please enter a valid name.")

11
settings1.json Normal file
View File

@ -0,0 +1,11 @@
{
"system_prompt": "You are an OKR coach and support us, as beginners in OKRs, with the correct phrasing of OKRs.",
"input_template": "We want to improve our SLA framework by finalizing the current SLA template...",
"prompt_template": "Please help us in defining proper OKRs. Here is what we have thought about and we would like to phrase an OKR with max. 4 key results. this is the user input: {user_input} Please provide the response in json format. Objective (key: objective) key results (list with the key results)",
"num_key_results": 4,
"team_members": [
"John Doe",
"Jane Smith"
],
"team_member_template": "{name} - Team Member"
}

12
styles.py Normal file
View File

@ -0,0 +1,12 @@
import streamlit as st
def apply_styles():
page_bg_color = """
<style>
body {
background-color: #002F5F;
color: white;
}
</style>
"""
st.markdown(page_bg_color, unsafe_allow_html=True)

42
test.ipynb Normal file
View File

@ -0,0 +1,42 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"hello\n"
]
}
],
"source": [
"print('hello')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

160
utils.py Normal file
View File

@ -0,0 +1,160 @@
import json
import streamlit as st
# Function to construct the prompt
def construct_prompt(prompt_template: str, user_input: str) -> str:
return prompt_template.format(user_input=user_input)
'''# Function to extract and parse JSON response
def extract_llm_response(response):
print("response:", response)
try:
raw_message_content = response["choices"][0]["message"]["content"]
print("raw_message_content:", raw_message_content)
# Clean and parse the JSON content
cleaned_content = raw_message_content.replace("`", "").split("json")[-1]
# for debugging
#if debug:
# print("cleaned:", '-'*50)
# print(cleaned_content.strip())
def parse_json_content(cleaned_content: str):
"""
Parses the cleaned content to extract valid JSON data.
Args:
cleaned_content (str): The raw content containing JSON data.
Returns:
dict or list: The parsed JSON object.
"""
import re
# Step 1: Strip unwanted characters and clean the content
cleaned_content = cleaned_content.strip()
# Step 2: Use regex to extract only the valid JSON block (e.g., starts with [ or {)
json_match = re.search(r"(\{.*\}|\[.*\])", cleaned_content, re.DOTALL)
if not json_match:
raise ValueError("No valid JSON found in the content.")
# Step 3: Extract and parse the valid JSON
valid_json = json_match.group(0) # Extract matched JSON block
try:
extracted_data = json.loads(valid_json)
except json.JSONDecodeError as e:
raise ValueError(f"Failed to decode JSON. Error: {e}\nContent:\n{valid_json}")
return extracted_data
parsed_data = parse_json_content(cleaned_content=cleaned_content)
print("parsed_data:",parsed_data)
print("debug:", parsed_data.get("objective", ""))
#parsed_data = json.loads(cleaned_content)
return parsed_data.get("objective", ""), parsed_data.get("key_results", [])
except Exception as e:
st.error(f"Error parsing API response: {e}")
return "", []'''
import json
import re
def parse_json_content(cleaned_content: str):
"""
Parses the cleaned content to extract valid JSON data.
Args:
cleaned_content (str): The raw content containing JSON data.
Returns:
dict or list: The parsed JSON object.
"""
import re
# Step 1: Strip unwanted characters and clean the content
cleaned_content = cleaned_content.strip()
# Step 2: Use regex to extract only the valid JSON block (e.g., starts with [ or {)
json_match = re.search(r"(\{.*\}|\[.*\])", cleaned_content, re.DOTALL)
if not json_match:
raise ValueError("No valid JSON found in the content.")
# Step 3: Extract and parse the valid JSON
valid_json = json_match.group(0) # Extract matched JSON block
try:
extracted_data = json.loads(valid_json)
except json.JSONDecodeError as e:
raise ValueError(f"Failed to decode JSON. Error: {e}\nContent:\n{valid_json}")
return extracted_data
# Function to extract and parse JSON response
def extract_llm_response(response):
"""
Extracts and parses the JSON response from the API.
Args:
response (dict): The API response containing a hint and proposals.
Returns:
tuple: A tuple containing the objective (str), key results (list), and hint (str).
"""
print("RESPONSE:",response)
raw_message_content = response["choices"][0]["message"]["content"]
print("raw_message_content:", raw_message_content)
# Clean and parse the JSON content
cleaned_content = raw_message_content.replace("`", "").split("json")[-1]
print("cleaned content", cleaned_content)
parsed_data = parse_json_content(cleaned_content=cleaned_content)
print("parsed_data:",parsed_data)
hint = parsed_data.get("hint", "")
proposals = parsed_data.get("proposals", [])
if proposals:
# Extract the first proposal's objective and key results
first_proposal = proposals[0] # Get the first proposal (assuming it's a list)
objective = first_proposal.get("objective", "")
key_results = first_proposal.get("key_results", [])
else:
objective = ""
key_results = []
#print("debug:", parsed_data.get("objective", ""))
return objective, key_results, hint
#try:
# Extract hint from the response
hint = response.get("hint", "")
# Extract proposals from the response
proposals = response.get("proposals", [])
print("hint:", hint)
print("proposals:", proposals)
# Check if proposals are available
if proposals:
# Extract the first proposal's objective and key results
first_proposal = proposals[0] # Get the first proposal (assuming it's a list)
objective = first_proposal.get("objective", "")
key_results = first_proposal.get("key_results", [])
else:
objective = ""
key_results = []
# Log parsed data for debugging
print("parsed_data:", {"objective": objective, "key_results": key_results, "hint": hint})
return objective, key_results, hint
#except Exception as e:
# print(f"Error parsing API response: {e}")
# return "", [], ""