Add complete Crumbforest mission system
- Interactive mission selector with metadata-driven design - 5 educational missions (basics + advanced) - AI assistant roles (Deepbit, Bugsy, Schnippsi, Tobi) - SnakeCam gesture recognition system - Token tracking utilities - CLAUDE.md documentation - .gitignore for logs and secrets
This commit is contained in:
52
snake_camera_vision/app.py
Executable file
52
snake_camera_vision/app.py
Executable file
@@ -0,0 +1,52 @@
|
||||
from flask import Flask, render_template, Response, request, redirect
|
||||
import cv2
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
def gen_frames():
|
||||
cam = cv2.VideoCapture(0)
|
||||
if not cam.isOpened():
|
||||
print("[WARNUNG] Kamera konnte nicht geöffnet werden.")
|
||||
return
|
||||
|
||||
try:
|
||||
while True:
|
||||
success, frame = cam.read()
|
||||
if not success:
|
||||
break
|
||||
ret, buffer = cv2.imencode('.jpg', frame)
|
||||
frame = buffer.tobytes()
|
||||
yield (b'--frame\r\n'
|
||||
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
|
||||
finally:
|
||||
cam.release()
|
||||
print("[info] Kamera wurde sauber freigegeben.")
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
||||
@app.route('/video_feed')
|
||||
def video_feed():
|
||||
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
|
||||
|
||||
@app.route('/log_answer', methods=['POST'])
|
||||
def log_answer():
|
||||
user_input = request.form.get('antwort', 'nichts gesagt')
|
||||
mood = request.form.get('mood', 'unspecified')
|
||||
gesture = request.form.get('gesture', 'none')
|
||||
timestamp = datetime.now().isoformat()
|
||||
|
||||
log_entry = {
|
||||
'timestamp': timestamp,
|
||||
'antwort': user_input,
|
||||
'mood': mood,
|
||||
'gesture': gesture
|
||||
}
|
||||
|
||||
with open("snake_log.jsonl", "a") as log_file:
|
||||
log_file.write(json.dumps(log_entry) + "\n")
|
||||
|
||||
return redirect("/")
|
||||
13
snake_camera_vision/camera_stream.py
Executable file
13
snake_camera_vision/camera_stream.py
Executable file
@@ -0,0 +1,13 @@
|
||||
import cv2
|
||||
|
||||
def gen_frames():
|
||||
cap = cv2.VideoCapture(0)
|
||||
while True:
|
||||
success, frame = cap.read()
|
||||
if not success:
|
||||
break
|
||||
else:
|
||||
ret, buffer = cv2.imencode('.jpg', frame)
|
||||
frame = buffer.tobytes()
|
||||
yield (b'--frame\r\n'
|
||||
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
|
||||
3
snake_camera_vision/run.sh
Executable file
3
snake_camera_vision/run.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
echo "🐍 Starte SnakeCam ..."
|
||||
exec python3 app.py
|
||||
15
snake_camera_vision/snakecam_module.py
Executable file
15
snake_camera_vision/snakecam_module.py
Executable file
@@ -0,0 +1,15 @@
|
||||
# snakecam_module.py
|
||||
import cv2
|
||||
|
||||
def init_camera(index=0):
|
||||
cam = cv2.VideoCapture(index)
|
||||
if not cam.isOpened():
|
||||
print("[WARNUNG] Kamera konnte nicht geöffnet werden.")
|
||||
return None
|
||||
print("[OK] Kamera erfolgreich geöffnet.")
|
||||
return cam
|
||||
|
||||
def release_camera(cam):
|
||||
if cam and cam.isOpened():
|
||||
cam.release()
|
||||
print("[INFO] Kamera wurde freigegeben.")
|
||||
9
snake_camera_vision/static/styles.css
Executable file
9
snake_camera_vision/static/styles.css
Executable file
@@ -0,0 +1,9 @@
|
||||
body {
|
||||
background-color: #f0fff0;
|
||||
font-family: 'Comic Sans MS', cursive, sans-serif;
|
||||
text-align: center;
|
||||
color: #006400;
|
||||
}
|
||||
h1 {
|
||||
margin-top: 20px;
|
||||
}
|
||||
80
snake_camera_vision/templates/index.html
Executable file
80
snake_camera_vision/templates/index.html
Executable file
@@ -0,0 +1,80 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>🐍 SnakeCam – Krümelblick ins Versteck</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Comic Sans MS', sans-serif;
|
||||
background-color: #e9f5e9;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
img {
|
||||
border: 4px dashed #4caf50;
|
||||
border-radius: 12px;
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
form {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
input, select {
|
||||
padding: 0.5rem;
|
||||
font-size: 1rem;
|
||||
margin: 0.5rem;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
button {
|
||||
padding: 0.7rem 1.2rem;
|
||||
font-size: 1rem;
|
||||
background-color: #4caf50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #388e3c;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h1>🐍 SnakeCam</h1>
|
||||
<p>Willkommen kleiner Krümel! Hier siehst du, was deine Kamera entdeckt.</p>
|
||||
|
||||
<!-- Live-Stream -->
|
||||
<img src="/video_feed" alt="Live-Übertragung von SnakeCam 🐍" />
|
||||
|
||||
<!-- Eingabeformular -->
|
||||
<form action="/log_answer" method="POST">
|
||||
<p><strong>Was fühlst du gerade?</strong></p>
|
||||
<input type="text" name="antwort" placeholder="Ich sehe einen ... 🐞🌳🤖" required>
|
||||
|
||||
<p><strong>Wie ist deine Stimmung?</strong></p>
|
||||
<select name="mood">
|
||||
<option value="happy">😊 Glücklich</option>
|
||||
<option value="curious">🤔 Neugierig</option>
|
||||
<option value="calm">😌 Ruhig</option>
|
||||
<option value="excited">😃 Aufgeregt</option>
|
||||
<option value="unspecified">🤷 Keine Angabe</option>
|
||||
</select>
|
||||
|
||||
<p><strong>Hast du eine Geste gemacht?</strong></p>
|
||||
<select name="gesture">
|
||||
<option value="none">🚫 Keine</option>
|
||||
<option value="wave">👋 Winken</option>
|
||||
<option value="thumbs_up">👍 Daumen hoch</option>
|
||||
<option value="peace">✌️ Peace</option>
|
||||
<option value="other">✨ Etwas anderes</option>
|
||||
</select>
|
||||
|
||||
<br><br>
|
||||
<button type="submit">🎯 Eintragen</button>
|
||||
</form>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user