ktf-ai-test / app.py
BlindKnifemaker's picture
Update app.py
43cfdee verified
import gradio as gr
import json, csv, os, hashlib
from datetime import datetime
ADMIN_HASH = "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918" # "admin"
RESULTS = "vysledky.csv"
FEEDBACK = "zpetna_vazba.csv"
for f, cols in [(RESULTS, ['cas','kod','typ','skore','max','procenta','odpovedi']),
(FEEDBACK, ['cas','kod','typ','obt_testu','sroz_testu','uzit_testu','obt_vyuky','sroz_vyuky','uzit_vyuky','komentar'])]:
if not os.path.exists(f):
with open(f, 'w', newline='', encoding='utf-8') as file:
csv.writer(file).writerow(cols)
TESTS = {
"STAFF": {
"nazev": "Test pro administrativní pracovníky (STAFF)",
"questions": [
{
"q": "Jaká je doporučená struktura efektivního promptu pro práci s AI?",
"ctx": "Prompt je instrukce, kterou AI zadáváte. Jeho struktura ovlivňuje kvalitu odpovědí.",
"opts": [
"A) Role + Kontext + Úkol + Formát",
"B) Pouze úkol, ostatní AI domyslí sama",
"C) Poskytnutí jasné role AI zlepšuje kvalitu odpovědí",
"D) Formát výstupu není důležitý",
"E) Kontext pomáhá AI lépe pochopit situaci"
],
"ans": ["A","C","E"]
},
{
"q": "Co přesně znamená termín 'zero-shot prompting'?",
"ctx": "Zero-shot je základní technika práce s AI, kdy modelu poskytujeme pouze instrukci bez dalších příkladů.",
"opts": [
"A) Poskytnutí jednoho vzorového příkladu",
"B) Zadání instrukce bez jakýchkoliv příkladů",
"C) Poskytnutí tří vzorových příkladů",
"D) Nejjednodušší forma práce s AI",
"E) Vždy poskytuje nejlepší výsledky"
],
"ans": ["B","D"]
},
{
"q": "Co je 'answer pressure testing' a k čemu slouží?",
"ctx": "Answer pressure testing je technika, kterou testujeme spolehlivost odpovědí AI a snižujeme riziko chyb.",
"opts": [
"A) Technika pro zrychlení generování odpovědí",
"B) Žádost, aby AI zkontrolovala a zdůvodnila své odpovědi",
"C) Příklad: 'Jsi si tímto výsledkem jistý? Zkontroluj svoje úvahy.'",
"D) Pomáhá odhalit případné halucinace AI",
"E) Snižuje kvalitu odpovědí tím, že AI zmate"
],
"ans": ["B","C","D"]
},
{
"q": "Které z následujících úkolů lze bezpečně řešit pomocí AI v kancelářské práci?",
"ctx": "AI je užitečná pro mnoho úkolů, ale ne všechny jsou pro ni vhodné nebo bezpečné.",
"opts": [
"A) Shrnutí dlouhých dokumentů do kratší formy",
"B) Extrakce konkrétních informací (jména, data, částky) z dokumentů",
"C) Anonymizace osobních údajů v dokumentech",
"D) Fyzická archivace papírových dokumentů",
"E) Překlad textů a změna stylu komunikace"
],
"ans": ["A","B","C","E"]
},
{
"q": "Co přesně jsou 'halucinace' v kontextu AI systémů?",
"ctx": "Halucinace jsou jedním z nejzávažnějších rizik při práci s AI a je důležité jim porozumět.",
"opts": [
"A) AI vymýšlí informace, které vypadají věrohodně, ale jsou nepravdivé",
"B) Halucinace jsou vždy snadno rozpoznatelné",
"C) Je nezbytné vždy ověřovat důležitá fakta z jiných zdrojů",
"D) Answer pressure testing může pomoci odhalit halucinace",
"E) Nové modely AI už halucinace nemají"
],
"ans": ["A","C","D"]
},
{
"q": "Co je 'token' a proč je tento pojem důležitý?",
"ctx": "Token je základní jednotka, se kterou AI systémy pracují. Pochopení tokenů je klíčové pro efektivní práci s AI.",
"opts": [
"A) Token odpovídá přibližně 4 znakům textu",
"B) Token je základní jednotka zpracování textu v AI",
"C) Token je měna pro placení AI služeb",
"D) AI modely mají limit na počet tokenů",
"E) Token je totéž co jedno slovo"
],
"ans": ["A","B","D"]
},
{
"q": "Jak správně pracovat s AI při respektování GDPR?",
"ctx": "GDPR chrání osobní údaje občanů EU. Při práci s AI je nutné dodržovat tyto právní požadavky.",
"opts": [
"A) Anonymizovat všechny osobní údaje před nahráním do AI",
"B) GDPR se na práci s AI nevztahuje",
"C) Nikdy neposílat citlivá data do veřejných AI systémů",
"D) Znát politiku zpracování dat AI platformy",
"E) Osobní údaje lze do AI nahrávat bez omezení"
],
"ans": ["A","C","D"]
},
{
"q": "Jak správně pracovat s češtinou vs. angličtinou při použití AI?",
"ctx": "Volba jazyka ovlivňuje kvalitu odpovědí AI systémů, protože byly trénovány primárně na anglických datech.",
"opts": [
"A) Pro češtinu explicitně uvést 'v češtině'",
"B) AI automaticky rozpozná jazyk vždy správně",
"C) Pro vědu preferovat angličtinu",
"D) Kvalita je stejná pro všechny jazyky",
"E) Lze kombinovat jazyky podle potřeby"
],
"ans": ["A","C","E"]
},
{
"q": "Co znamená 'chain-of-thought prompting' a kdy ho použít?",
"ctx": "Chain-of-thought je pokročilá technika, kdy žádáme AI o postupné vysvětlení jednotlivých kroků řešení.",
"opts": [
"A) Žádost o postupné vysvětlení kroků",
"B) Nejrychlejší způsob generování",
"C) Užitečné pro komplexní analýzy",
"D) Příklad: 'Analyzuj: 1) témata 2) problémy 3) řešení'",
"E) Nevhodné pro analytické úlohy"
],
"ans": ["A","C","D"]
},
{
"q": "Co je 'role-playing' v kontextu práce s AI?",
"ctx": "Role-playing je technika, kdy AI přiřazujeme konkrétní roli či identitu, což ovlivňuje styl a obsah odpovědí.",
"opts": [
"A) AI přiřadíte konkrétní roli",
"B) Příklad: 'Jsi zkušený HR manažer s 20 lety praxe'",
"C) Role nijak neovlivňuje odpovědi",
"D) Role pomáhá přizpůsobit jazyk a odbornost",
"E) Používá se pouze pro zábavu"
],
"ans": ["A","B","D"]
}
]
},
"ACADEMIC": {
"nazev": "Test pro akademické pracovníky (ACADEMIC)",
"questions": [
{
"q": "Jaká je struktura akademického promptu?",
"ctx": "Akademická práce vyžaduje přesnější a rigoróznější strukturu promptů než běžné použití AI.",
"opts": [
"A) Role + Kontext + Úkol + Formát + Omezení",
"B) Pouze úkol",
"C) Požadavek na rozlišení fakta/interpretace",
"D) Žádost o označení míry jistoty",
"E) Formát není důležitý"
],
"ans": ["A","C","D"],
"pts": 1
},
{
"q": "Co je 'answer pressure testing' a proč je v akademii kritický?",
"ctx": "V akademickém kontextu je spolehlivost informací zásadní, proto je answer pressure testing klíčovou technikou.",
"opts": [
"A) Technika systematického zpochybňování",
"B) Příklad: 'Jsi si jistý? Odkud to? Alternativy?'",
"C) Pomáhá odhalit halucinace",
"D) V akademii méně důležitý než v kanceláři",
"E) Nutí AI přiznat nejistotu"
],
"ans": ["A","B","C","E"],
"pts": 1
},
{
"q": "Proč jsou halucinace v akademii zvlášť problematické?",
"ctx": "V akademickém výzkumu může jediná chyba diskreditovat celou práci. Halucinace AI představují závažné riziko.",
"opts": [
"A) Jedna vymyšlená citace diskredituje celou práci",
"B) V nových modelech již vyřešeny",
"C) AI prezentuje vymyšlené info přesvědčivě",
"D) Týkají se především citací a faktů",
"E) Jsou vždy snadno rozpoznatelné"
],
"ans": ["A","C","D"],
"pts": 1
},
{
"q": "Rozdíl mezi 'asistencí' a 'nahrazením úsudku'?",
"ctx": "V akademické práci je klíčové rozlišovat, kdy AI pomáhá a kdy za nás myslí. To má etické i metodologické důsledky.",
"opts": [
"A) Asistence = AI strukturuje MOJE myšlenky",
"B) Nahrazení = AI vytváří závěry které přebírám",
"C) V akademii irelevantní",
"D) Asistence = finální odpovědnost na mně",
"E) Oba postupy stejně přijatelné"
],
"ans": ["A","B","D"],
"pts": 1
},
{
"q": "Jak správně pracovat s AI a GDPR v akademickém výzkumu?",
"ctx": "Akademický výzkum často pracuje s citlivými daty respondentů. GDPR stanovuje přísné požadavky na jejich ochranu.",
"opts": [
"A) Anonymizovat data před nahráním",
"B) Data z výzkumu lze nahrávat bez omezení",
"C) Necitlivá data respondentů do veřejných AI",
"D) Enterprise AI nabízí lepší ochranu",
"E) GDPR se na akademii nevztahuje"
],
"ans": ["A","C","D"],
"pts": 1
},
{
"q": "Proč je pro akademii doporučena angličtina?",
"ctx": "AI modely byly trénovány primárně na anglických akademických textech, což má důsledky pro kvalitu odpovědí.",
"opts": [
"A) AI trénovány primárně na anglických akademických textech",
"B) Kvalita v češtině a angličtině je stejná",
"C) Pro vědu přesnější odpovědi v angličtině",
"D) Pro admin práci lepší čeština",
"E) Angličtina není důležitá"
],
"ans": ["A","C","D"],
"pts": 1
},
{
"q": "Které použití AI je přijatelné a které ne?",
"ctx": "V akademické práci existují jasné hranice mezi přijatelným a nepřijatelným použitím AI. Je klíčové je rozlišovat.",
"opts": [
"A) PŘIJATELNÉ: Návrh struktury mých myšlenek",
"B) PŘIJATELNÉ: Generování závěrů výzkumu",
"C) PŘIJATELNÉ: Identifikace slabých míst argumentace",
"D) NEPŘIJATELNÉ: Auto-psaní sekcí bez kontroly",
"E) PŘIJATELNÉ: Delegování hodnotových soudů"
],
"ans": ["A","C","D"],
"pts": 1.5
},
{
"q": "Jak pracovat s epistemickou nejistotou?",
"ctx": "AI systémy nemají skutečné porozumění a často si nejsou jisté. Musíme s touto nejistotou pracovat systematicky.",
"opts": [
"A) Požadovat explicitní míru jistoty",
"B) Důvěřovat autoritativnímu tónu AI",
"C) Ověřovat tvrzení z primárních zdrojů",
"D) Žádat alternativní interpretace",
"E) AI jako konečný arbitr"
],
"ans": ["A","C","D"],
"pts": 1.5
},
{
"q": "Jak správně pracovat se zdroji a citacemi?",
"ctx": "AI systémy mají tendenci vymýšlet realisticky vypadající citace. To představuje závažné riziko pro akademickou integritu.",
"opts": [
"A) AI často vymýšlí věrohodné citace",
"B) Každou citaci ověřit v databázích",
"C) Answer pressure: 'Odkud? Je DOI platné?'",
"D) Citace z AI spolehlivé pro publikování",
"E) Preferovat: PDF → shrnutí, ne 'cituj studie'"
],
"ans": ["A","B","C","E"],
"pts": 1.5
},
{
"q": "Co musí akademik uvést ohledně použití AI?",
"ctx": "Transparentnost je základem akademické integrity. Použití AI nástrojů musí být jasně deklarováno.",
"opts": [
"A) Neuvádí se",
"B) Transparentně uvést v metodologii",
"C) AI je nástroj, ne autor - ale uvést použití",
"D) Citovat AI podle standardů (APA)",
"E) Závisí na pravidlech instituce"
],
"ans": ["B","C","D","E"],
"pts": 1.5
},
{
"q": "Proč AI nemá 'skutečné porozumění'?",
"ctx": "Pochopení limitů AI je klíčové pro její zodpovědné použití v akademickém kontextu.",
"opts": [
"A) AI je statistický predikční model",
"B) Předpovídá pokračování textu z vzorců",
"C) Když neví, stejně něco vygeneruje",
"D) Nové modely už mají lidské porozumění",
"E) Proto nutná epistemická opatrnost"
],
"ans": ["A","B","C","E"],
"pts": 1.5
},
{
"q": "Jaká je role AI v akademickém výzkumu?",
"ctx": "Je důležité správně definovat roli AI v akademické práci - co může a co nemůže dělat.",
"opts": [
"A) Pomocný nástroj pro strukturování",
"B) Náhrada za odborný úsudek",
"C) Kritický partner pro zpochybňování",
"D) Autoritativní zdroj pravdy",
"E) Nástroj pro podporu, ne nahrazení"
],
"ans": ["A","C","E"],
"pts": 1.5
}
]
}
}
def check(pwd):
return hashlib.sha256(pwd.encode()).hexdigest() == ADMIN_HASH
def score(typ, ans):
correct = sum(q.get("pts",1) for i,q in enumerate(TESTS[typ]["questions"])
if set(ans.get(f"q_{i}",[]))==set(q["ans"]))
total = sum(q.get("pts",1) for q in TESTS[typ]["questions"])
return correct, total
def save_result(kod, typ, sc, mx, ans):
with open(RESULTS, 'a', newline='', encoding='utf-8') as f:
csv.writer(f).writerow([datetime.now().isoformat(), kod, typ, sc, mx,
f"{sc/mx*100:.1f}%", json.dumps(ans, ensure_ascii=False)])
def save_fb(kod, typ, ot, st, ut, ov, sv, uv, kom):
with open(FEEDBACK, 'a', newline='', encoding='utf-8') as f:
csv.writer(f).writerow([datetime.now().isoformat(), kod, typ, ot, st, ut, ov, sv, uv, kom])
def get_file(pwd, which):
if not check(pwd):
return None, "❌ Špatné heslo"
file = RESULTS if which=="r" else FEEDBACK
if not os.path.exists(file):
return None, "📭 Zatím žádná data"
return file, f"✅ {file} připraven ke stažení"
with gr.Blocks(title="Test AI KTF") as app:
gr.Markdown("# 🎓 Test znalostí: Generativní AI\n**Katolická teologická fakulta UK, Praha 2025**")
kod_s, typ_s = gr.State(""), gr.State("")
with gr.Tab("🔐 Start"):
gr.Markdown("### Zahájení testu")
gr.Markdown("Pro zahájení zadejte váš unikátní kód a vyberte typ testu.")
kod = gr.Textbox(label="Váš unikátní kód", placeholder="KTF2025-001", info="Tento kód obdržíte od organizátora")
typ = gr.Radio([
("STAFF - Administrativní pracovníci (10 otázek)", "STAFF"),
("ACADEMIC - Výzkumní pracovníci (12 otázek)", "ACADEMIC")
], label="Typ testu", info="Vyberte test odpovídající vaší roli")
go = gr.Button("Začít test", variant="primary", size="lg")
msg = gr.Markdown("")
with gr.Tab("📝 Test"):
info = gr.Markdown("")
qs = []
for i in range(12):
with gr.Group(visible=False) as g:
qt = gr.Markdown("")
qctx = gr.Markdown("", elem_classes="question-context")
qc = gr.CheckboxGroup(label="⚠️ Vyberte VŠECHNY správné odpovědi")
qs.append((g,qt,qctx,qc))
send = gr.Button("Odeslat test", variant="primary", size="lg", visible=False)
send_msg = gr.Markdown("")
with gr.Tab("📊 Výsledky"):
res = gr.Markdown("")
gr.Markdown("---")
gr.Markdown("### 💬 Zpětná vazba")
gr.Markdown("*Vaše zpětná vazba je anonymní a pomůže nám zlepšit jak test, tak celou výuku.*")
gr.Markdown("#### Hodnocení testu:")
obt_t = gr.Radio(["Příliš snadný", "Přiměřený", "Příliš těžký"], label="Obtížnost testu")
sroz_t = gr.Radio(["Výborná", "Dobrá", "Špatná"], label="Srozumitelnost otázek")
uzit_t = gr.Radio(["Velmi užitečný", "Užitečný", "Málo užitečný"], label="Užitečnost testu pro praxi")
gr.Markdown("#### Hodnocení výuky (kurzu AI):")
obt_v = gr.Radio(["Příliš snadná", "Přiměřená", "Příliš těžká"], label="Obtížnost výuky")
sroz_v = gr.Radio(["Výborná", "Dobrá", "Špatná"], label="Srozumitelnost výkladu")
uzit_v = gr.Radio(["Velmi užitečná", "Užitečná", "Málo užitečná"], label="Užitečnost pro praxi")
kom = gr.Textbox(label="Váš komentář (nepovinné)", placeholder="Sdílejte své postřehy k testu nebo výuce...", lines=3)
fb = gr.Button("Odeslat zpětnou vazbu", variant="secondary")
fb_msg = gr.Markdown("")
with gr.Tab("👨‍💼 Admin"):
gr.Markdown("### 🔒 Administrátorský přístup")
gr.Markdown("*Pouze pro organizátory kurzu - stahování výsledků*")
pwd = gr.Textbox(label="Admin heslo", type="password", placeholder="Výchozí: admin")
with gr.Row():
dlr = gr.Button("📥 Stáhnout výsledky testů")
dlf = gr.Button("📥 Stáhnout zpětnou vazbu")
dl = gr.File(label="CSV soubor ke stažení")
dlm = gr.Markdown("")
gr.Markdown("*Pro změnu hesla upravte ADMIN_HASH v app.py*")
def start(k, t):
if not k or not t:
return {msg: "❌ Prosím vyplňte kód i typ testu", kod_s: "", typ_s: ""}
test = TESTS[t]
upd = {
msg: f"✅ Test byl zahájen! **→ Přejděte na záložku 'Test'**",
kod_s: k,
typ_s: t,
info: f"## {test['nazev']}\n\n**Počet otázek:** {len(test['questions'])}\n\n⚠️ **Důležité:** U každé otázky označte VŠECHNY správné odpovědi!",
send: gr.update(visible=True),
send_msg: ""
}
for i in range(12):
if i < len(test["questions"]):
q = test["questions"][i]
upd[qs[i][0]] = gr.update(visible=True)
upd[qs[i][1]] = f"### Otázka {i+1}\n\n{q['q']}"
upd[qs[i][2]] = f"*{q.get('ctx', '')}*"
upd[qs[i][3]] = gr.update(choices=q["opts"], value=[])
else:
upd[qs[i][0]] = gr.update(visible=False)
return upd
def submit(k, t, *a):
if not k:
return "❌ Chyba: Test nebyl správně zahájen", ""
ans = {f"q_{i}": a[i] for i in range(len(TESTS[t]["questions"]))}
sc, mx = score(t, ans)
save_result(k, t, sc, mx, ans)
ok = sc >= (7 if t=="STAFF" else 8)
poz = "minimálně 7 bodů" if t=="STAFF" else "minimálně 8 bodů"
result = f"""## {'✅ Gratulujeme! Test úspěšně splněn!' if ok else '❌ Test nesplněn'}
**Váš výsledek:** {sc:.1f} / {mx} bodů ({sc/mx*100:.1f}%)
**Požadavek pro splnění:** {poz}
{'🎉 **Úspěšně jste absolvovali test!**' if ok else '😔 Bohužel jste nedosáhli minimálního počtu bodů. Doporučujeme prostudovat materiály a zkusit test znovu.'}
---
**📊 Podrobnosti:**
- Kód účastníka: {k}
- Typ testu: {t}
- Datum a čas: {datetime.now().strftime('%d.%m.%Y v %H:%M')}
---
### ⬇️ Co dál?
**Prosím, poskytněte nám zpětnou vazbu níže** - pomůžete nám zlepšit jak test, tak celou výuku. Zpětná vazba je anonymní a zabere jen 2 minuty. Děkujeme! 🙏
"""
nav_msg = "# ✅ Test odeslán!\n\n**→ Přejděte na záložku 'Výsledky' pro zobrazení výsledků a zpětnou vazbu**"
return result, nav_msg
go.click(start, [kod,typ],
[msg,kod_s,typ_s,info,send,send_msg]+[x for g in qs for x in g])
send.click(submit, [kod_s,typ_s]+[q[3] for q in qs], [res, send_msg])
fb.click(lambda k,t,ot,st,ut,ov,sv,uv,c: (save_fb(k,t,ot,st,ut,ov,sv,uv,c), "✅ **Děkujeme za zpětnou vazbu!** Vaše připomínky jsou pro nás velmi cenné.")[1] if k else "❌ Nelze odeslat - test nebyl dokončen",
[kod_s,typ_s,obt_t,sroz_t,uzit_t,obt_v,sroz_v,uzit_v,kom], fb_msg)
dlr.click(lambda p: get_file(p,"r"), pwd, [dl,dlm])
dlf.click(lambda p: get_file(p,"f"), pwd, [dl,dlm])
app.launch()