added parameters to the proposer
started to refactor code to make it cleaner
This commit is contained in:
parent
9baf460c87
commit
6f09b9fe0b
16
api.py
16
api.py
@ -5,7 +5,8 @@ from dotenv import load_dotenv
|
|||||||
from settings import load_settings
|
from settings import load_settings
|
||||||
from utils import construct_prompt
|
from utils import construct_prompt
|
||||||
|
|
||||||
from config import INPUT_TEMPLATE, SYSTEM_PROMPT, PROMPT_TEMPLATE
|
#from config import SYSTEM_PROMPT, PROMPT_TEMPLATE
|
||||||
|
from config.config import INPUT_EXAMPLE, SYSTEM_PROMPT, PROMPT_TEMPLATE
|
||||||
|
|
||||||
# Load API key from .env file
|
# Load API key from .env file
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
@ -17,13 +18,12 @@ if not api_key:
|
|||||||
|
|
||||||
api_url = "https://genai.dev.odp.lhgroup.de/openai/deployments/gpt-4-turbo/chat/completions?api-version=2023-07-01-preview"
|
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):
|
def fetch_okrs(user_input: str, okr_cycle: str = 'JAN 25 to APR 25', num_key_results: int=3):
|
||||||
#settings = load_settings()
|
user_prompt = construct_prompt(
|
||||||
|
prompt_template=PROMPT_TEMPLATE,
|
||||||
#system_prompt = settings["system_prompt"]
|
user_input=user_input,
|
||||||
#input_template = settings["input_template"]
|
okr_cycle=okr_cycle,
|
||||||
|
num_key_results=num_key_results)
|
||||||
user_prompt = construct_prompt(prompt_template=PROMPT_TEMPLATE, user_input=user_input)
|
|
||||||
|
|
||||||
headers = {"api-key": api_key, "Content-Type": "application/json"}
|
headers = {"api-key": api_key, "Content-Type": "application/json"}
|
||||||
body = {
|
body = {
|
||||||
|
|||||||
14
config.py
14
config.py
@ -82,8 +82,8 @@ The json could be structured like this:
|
|||||||
|
|
||||||
PROMPT_TEMPLATE = """
|
PROMPT_TEMPLATE = """
|
||||||
Please help us in defining proper OKRs.
|
Please help us in defining proper OKRs.
|
||||||
Here is what we have thought about and we would like to phrase an OKR with maximum 5 key results.
|
Here is what we have thought about and we would like to phrase an OKR with {num_key_results} key results.
|
||||||
The next OKR cycle is from JAN 2025 till APR 2025.
|
The next OKR cycle is from {okr_cycle}
|
||||||
|
|
||||||
this is the user input:
|
this is the user input:
|
||||||
{user_input}
|
{user_input}
|
||||||
@ -99,8 +99,6 @@ We would like to improve this, to have a better steering function, e.g. by addin
|
|||||||
To achieve this, we need to develop a bonus concept which is viable, feasible and desirable.
|
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 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.
|
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 for user input
|
||||||
@ -129,4 +127,10 @@ team = [
|
|||||||
'Mareen Fox Rogers',
|
'Mareen Fox Rogers',
|
||||||
'Michelle Wehrli',
|
'Michelle Wehrli',
|
||||||
'Johannes Otto'
|
'Johannes Otto'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
cycle_definitions = {
|
||||||
|
'Cycle1': 'JAN 2025 to APR 2025',
|
||||||
|
'Cycle2': 'MAY 2025 to AUG 2025',
|
||||||
|
'Cycle3': 'SEP 2025 to DEC 2025'
|
||||||
|
}
|
||||||
0
config/__init__.py
Normal file
0
config/__init__.py
Normal file
69
config/config.py
Normal file
69
config/config.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
cycle_definitions = {
|
||||||
|
'Cycle1': 'JAN 2025 to APR 2025',
|
||||||
|
'Cycle2': 'MAY 2025 to AUG 2025',
|
||||||
|
'Cycle3': 'SEP 2025 to DEC 2025'
|
||||||
|
}
|
||||||
|
|
||||||
|
SYSTEM_PROMPT = """
|
||||||
|
You are an OKR coach who helps beginners create well-phrased OKRs (Objectives and Key Results).
|
||||||
|
Your goal is to provide a proposal for an OKR based on user input, formatted as JSON.
|
||||||
|
If the input is unclear or incomplete, include a hint with specific questions or suggestions
|
||||||
|
to help improve the input.
|
||||||
|
|
||||||
|
Always follow this format for your response:
|
||||||
|
{
|
||||||
|
"hint": "Suggestions or questions to improve the input, if needed. If no hint is needed, return an empty string.",
|
||||||
|
"proposal": [
|
||||||
|
{
|
||||||
|
"objective": "A clear and concise objective variant",
|
||||||
|
"key_results": ["Key result 1", "Key result 2", "... up to 5 key results"]
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Keep your responses concise, actionable, and aligned with OKR best practices. If you need more context from the user, ask for it in the `hint`.
|
||||||
|
Always provide a 'hint' how to further improve the user input in order to get better results.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 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 {num_key_results} key results.
|
||||||
|
The next OKR cycle is from {okr_cycle}
|
||||||
|
|
||||||
|
this is the user input:
|
||||||
|
{user_input}
|
||||||
|
|
||||||
|
Please provide the response in json format.
|
||||||
|
"""
|
||||||
|
|
||||||
|
INPUT_EXAMPLE = """
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
team = [
|
||||||
|
'Khanh Dinh',
|
||||||
|
'Roberto Renna',
|
||||||
|
'Suat Sonkur',
|
||||||
|
'Sven Eichmeyer',
|
||||||
|
'Robin Plitzko',
|
||||||
|
'Vikas Rathore',
|
||||||
|
'Nadia Kartascheff',
|
||||||
|
'Andreas Muheim',
|
||||||
|
'Christopher Koch',
|
||||||
|
'Andreas Pluess',
|
||||||
|
'Manfred Hahn',
|
||||||
|
'Michaela Schumacher',
|
||||||
|
'Sandra Pastoor',
|
||||||
|
'Mareen Fox Rogers',
|
||||||
|
'Michelle Wehrli',
|
||||||
|
'Johannes Otto'
|
||||||
|
]
|
||||||
76
proposer.py
76
proposer.py
@ -1,28 +1,40 @@
|
|||||||
import streamlit as st
|
import streamlit as st
|
||||||
from api import fetch_okrs
|
from api import fetch_okrs
|
||||||
from config import INPUT_TEMPLATE, team
|
#from config import INPUT_TEMPLATE, team, cycle_definitions
|
||||||
|
from config.config import INPUT_EXAMPLE, cycle_definitions, team
|
||||||
from utils import extract_llm_response
|
from utils import extract_llm_response
|
||||||
|
|
||||||
def proposer_page():
|
import json
|
||||||
# Streamlit App Layout
|
|
||||||
st.title("AO/PM OKR Proposer")
|
from ui.parameters import section_parameters
|
||||||
|
|
||||||
|
def section_user_input():
|
||||||
|
# section for input parameters
|
||||||
|
section_parameters()
|
||||||
|
|
||||||
# Input Section and Buttons Row
|
# Input Section and Buttons Row
|
||||||
st.subheader("Enter your idea or goal:")
|
st.subheader("Enter your idea or goal:")
|
||||||
user_input = st.text_area(
|
user_input = st.text_area(
|
||||||
"Input your idea here:",
|
"Input your idea here:",
|
||||||
value=st.session_state.get("user_input", INPUT_TEMPLATE.strip()),
|
value=st.session_state.get("user_input", INPUT_EXAMPLE.strip()),
|
||||||
height=300,
|
height=300,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
st.session_state['user_input'] = user_input
|
||||||
|
|
||||||
generate_okrs_clicked = st.button("Generate OKR Proposal")
|
generate_okrs_clicked = st.button("Generate OKR Proposal")
|
||||||
|
|
||||||
if generate_okrs_clicked:
|
if generate_okrs_clicked:
|
||||||
|
print("session_state:", st.session_state)
|
||||||
if not user_input.strip():
|
if not user_input.strip():
|
||||||
st.warning("Please provide some input before generating OKRs.")
|
st.warning("Please provide some input before generating OKRs.")
|
||||||
else:
|
else:
|
||||||
with st.spinner("Generating OKRs..."):
|
with st.spinner("Generating OKRs..."):
|
||||||
response = fetch_okrs(user_input=user_input)
|
response = fetch_okrs(
|
||||||
|
user_input=user_input,
|
||||||
|
okr_cycle=st.session_state['okr_cycle'],
|
||||||
|
num_key_results=st.session_state['num_key_results'])
|
||||||
|
|
||||||
if response:
|
if response:
|
||||||
# Extract Objective and Key Results from response
|
# Extract Objective and Key Results from response
|
||||||
objective, key_results, hint = extract_llm_response(response)
|
objective, key_results, hint = extract_llm_response(response)
|
||||||
@ -30,6 +42,7 @@ def proposer_page():
|
|||||||
st.session_state["key_results"] = key_results
|
st.session_state["key_results"] = key_results
|
||||||
st.session_state["hint"] = hint
|
st.session_state["hint"] = hint
|
||||||
|
|
||||||
|
def section_okr_proposals():
|
||||||
# Display Results Only if an OKR Has Been Generated
|
# Display Results Only if an OKR Has Been Generated
|
||||||
if "objective" in st.session_state and "key_results" in st.session_state:
|
if "objective" in st.session_state and "key_results" in st.session_state:
|
||||||
# Ensure team members exist in session state
|
# Ensure team members exist in session state
|
||||||
@ -52,7 +65,8 @@ def proposer_page():
|
|||||||
"Select Responsibles for Objective:",
|
"Select Responsibles for Objective:",
|
||||||
options=team_members,
|
options=team_members,
|
||||||
default=[],
|
default=[],
|
||||||
key="responsibles_objective"
|
key="responsibles_objective",
|
||||||
|
max_selections=1
|
||||||
)
|
)
|
||||||
|
|
||||||
# Display Key Results with Responsibles Below Each One
|
# Display Key Results with Responsibles Below Each One
|
||||||
@ -61,12 +75,18 @@ def proposer_page():
|
|||||||
responsibles_for_key_results = []
|
responsibles_for_key_results = []
|
||||||
|
|
||||||
for i, kr in enumerate(st.session_state["key_results"], start=1):
|
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}")
|
kr_text = st.text_area(
|
||||||
responsible_for_kr = st.multiselect(
|
label=f'KR{i}',
|
||||||
f"Select Responsibles for Key Result {i}:",
|
value=kr,
|
||||||
|
key=f"proposal_kr_{i}"
|
||||||
|
)
|
||||||
|
#kr_text = st.text_area(f"Key Result {i}:", value=kr, key=f"kr_{i}")
|
||||||
|
responsible_for_kr = st.pills(
|
||||||
|
label=f"Select Responsibles for Key Result {i}:",
|
||||||
options=team_members,
|
options=team_members,
|
||||||
default=[],
|
default=[],
|
||||||
key=f"responsibles_kr_{i}"
|
key=f"responsibles_kr_{i}",
|
||||||
|
selection_mode='multi'
|
||||||
)
|
)
|
||||||
|
|
||||||
key_result_boxes.append(kr_text)
|
key_result_boxes.append(kr_text)
|
||||||
@ -75,7 +95,7 @@ def proposer_page():
|
|||||||
# Finalize Button Center-Aligned
|
# Finalize Button Center-Aligned
|
||||||
if st.button("Finalize"):
|
if st.button("Finalize"):
|
||||||
finalized_objective = objective_text.strip()
|
finalized_objective = objective_text.strip()
|
||||||
finalized_key_results = [st.session_state[f"kr_{i+1}"].strip() for i in range(len(key_result_boxes))]
|
finalized_key_results = [st.session_state[f"proposal_kr_{i+1}"].strip() for i in range(len(key_result_boxes))]
|
||||||
|
|
||||||
# Append initials of responsibles to Objective and Key Results
|
# Append initials of responsibles to Objective and Key Results
|
||||||
responsibles_list_objective = responsible_for_objective
|
responsibles_list_objective = responsible_for_objective
|
||||||
@ -83,6 +103,7 @@ def proposer_page():
|
|||||||
initials_str_objective = ", ".join(initials_objective)
|
initials_str_objective = ", ".join(initials_objective)
|
||||||
|
|
||||||
finalized_objective = f"{initials_str_objective} {finalized_objective}"
|
finalized_objective = f"{initials_str_objective} {finalized_objective}"
|
||||||
|
st.session_state['finalized_objective'] = finalized_objective
|
||||||
|
|
||||||
finalized_key_results_with_initials = []
|
finalized_key_results_with_initials = []
|
||||||
for i, kr in enumerate(finalized_key_results):
|
for i, kr in enumerate(finalized_key_results):
|
||||||
@ -90,6 +111,7 @@ def proposer_page():
|
|||||||
initials_kr = [f"{''.join([part[0] for part in name.split()]).upper()}" for name in responsibles_list_kr]
|
initials_kr = [f"{''.join([part[0] for part in name.split()]).upper()}" for name in responsibles_list_kr]
|
||||||
initials_str_kr = ", ".join(initials_kr)
|
initials_str_kr = ", ".join(initials_kr)
|
||||||
finalized_key_results_with_initials.append(f"KR{i+1}: [{initials_str_kr}] {kr}")
|
finalized_key_results_with_initials.append(f"KR{i+1}: [{initials_str_kr}] {kr}")
|
||||||
|
st.session_state['finalized_key_results_with_initials'] = finalized_key_results_with_initials
|
||||||
|
|
||||||
# Display finalized data in non-editable format (full width)
|
# Display finalized data in non-editable format (full width)
|
||||||
st.subheader("Finalized Objective:")
|
st.subheader("Finalized Objective:")
|
||||||
@ -112,3 +134,33 @@ def proposer_page():
|
|||||||
language=None,
|
language=None,
|
||||||
wrap_lines=True
|
wrap_lines=True
|
||||||
)
|
)
|
||||||
|
export_data_as_json()
|
||||||
|
|
||||||
|
def export_data_as_json():
|
||||||
|
# Prepare data for export
|
||||||
|
finalized_key_results_with_initials = st.session_state.get('finalized_key_results_with_initials')
|
||||||
|
export_data = {
|
||||||
|
"user_input": st.session_state.get('user_input'),
|
||||||
|
"finalized_objective": st.session_state.get('finalized_objective'),
|
||||||
|
"key_results": [kr.split(':')[-1].strip() for kr in finalized_key_results_with_initials]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert data to JSON string
|
||||||
|
json_data = json.dumps(export_data, indent=4)
|
||||||
|
|
||||||
|
# Add a download button
|
||||||
|
st.download_button(
|
||||||
|
label="Download Finalized OKR",
|
||||||
|
data=json_data,
|
||||||
|
file_name="okr_data.json",
|
||||||
|
mime="application/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
def proposer_page():
|
||||||
|
# Streamlit App Layout
|
||||||
|
st.title("AO/PM OKR Proposer")
|
||||||
|
|
||||||
|
section_user_input()
|
||||||
|
|
||||||
|
section_okr_proposals()
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import streamlit as st
|
import streamlit as st
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from config import SYSTEM_PROMPT, INPUT_TEMPLATE, PROMPT_TEMPLATE, team
|
from config.config import SYSTEM_PROMPT, INPUT_EXAMPLE, PROMPT_TEMPLATE, team
|
||||||
|
|
||||||
'''
|
'''
|
||||||
def settings_page():
|
def settings_page():
|
||||||
st.title("Settings")
|
st.title("Settings")
|
||||||
@ -100,7 +101,7 @@ def load_settings():
|
|||||||
# Default settings
|
# Default settings
|
||||||
return {
|
return {
|
||||||
"system_prompt": SYSTEM_PROMPT,
|
"system_prompt": SYSTEM_PROMPT,
|
||||||
"input_template": INPUT_TEMPLATE,
|
"input_template": INPUT_EXAMPLE,
|
||||||
"prompt_template": PROMPT_TEMPLATE,
|
"prompt_template": PROMPT_TEMPLATE,
|
||||||
"num_key_results": 4,
|
"num_key_results": 4,
|
||||||
"team_members": ["Khanh Dinh", "Robin Plitzko", "Roberto Renna"],
|
"team_members": ["Khanh Dinh", "Robin Plitzko", "Roberto Renna"],
|
||||||
|
|||||||
0
ui/__init__.py
Normal file
0
ui/__init__.py
Normal file
24
ui/parameters.py
Normal file
24
ui/parameters.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import streamlit as st
|
||||||
|
from config.config import cycle_definitions
|
||||||
|
|
||||||
|
def section_parameters():
|
||||||
|
st.subheader(body='Parameters for the OKR')
|
||||||
|
|
||||||
|
# Requested Parameter - Number of Key Results
|
||||||
|
num_key_results = st.number_input(
|
||||||
|
label='Please provide the number of key results',
|
||||||
|
min_value=1,
|
||||||
|
max_value=5,
|
||||||
|
key='num_key_results',
|
||||||
|
value=3
|
||||||
|
)
|
||||||
|
|
||||||
|
# Requested Parameter - OKR Cycle
|
||||||
|
options = [f"{key} ({value})" for key, value in cycle_definitions.items()]
|
||||||
|
okr_cycle = st.segmented_control(
|
||||||
|
label="Please select the OKR cycle",
|
||||||
|
options=options,
|
||||||
|
selection_mode="single",
|
||||||
|
default=options[0]
|
||||||
|
)
|
||||||
|
st.session_state['okr_cycle'] = okr_cycle
|
||||||
12
utils.py
12
utils.py
@ -3,8 +3,16 @@ import streamlit as st
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
# Function to construct the prompt
|
# Function to construct the prompt
|
||||||
def construct_prompt(prompt_template: str, user_input: str) -> str:
|
def construct_prompt(
|
||||||
return prompt_template.format(user_input=user_input)
|
prompt_template: str,
|
||||||
|
user_input: str,
|
||||||
|
okr_cycle: str = 'JAN 25 to APR 25',
|
||||||
|
num_key_results: int = 3 ) -> str:
|
||||||
|
|
||||||
|
return prompt_template.format(
|
||||||
|
user_input=user_input,
|
||||||
|
okr_cycle=okr_cycle,
|
||||||
|
num_key_results=num_key_results)
|
||||||
|
|
||||||
|
|
||||||
def parse_json_content(cleaned_content: str):
|
def parse_json_content(cleaned_content: str):
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user