| from flask import Flask, request, jsonify, abort, render_template, g
|
| from flask_cors import CORS
|
| import sqlite3, json, random, uuid, datetime, os
|
|
|
| app = Flask(__name__)
|
| CORS(app)
|
|
|
| DB_PATH = os.path.abspath("data.db")
|
| CONFIG = json.load(open("config.json", encoding="utf-8"))
|
|
|
|
|
| def get_db():
|
| if "db" not in g:
|
| g.db = sqlite3.connect(
|
| DB_PATH,
|
| timeout=10,
|
| check_same_thread=False
|
| )
|
| g.db.execute("PRAGMA journal_mode=WAL;")
|
| g.db.execute("PRAGMA synchronous=NORMAL;")
|
| return g.db
|
|
|
| @app.teardown_appcontext
|
| def close_db(e=None):
|
| db = g.pop("db", None)
|
| if db:
|
| db.close()
|
|
|
| def init_db():
|
| with sqlite3.connect(DB_PATH) as con:
|
| con.execute("""
|
| CREATE TABLE IF NOT EXISTS api_keys (
|
| key TEXT PRIMARY KEY,
|
| requests INTEGER DEFAULT 0,
|
| last_day TEXT
|
| )""")
|
| con.execute("""
|
| CREATE TABLE IF NOT EXISTS messages (
|
| id INTEGER PRIMARY KEY AUTOINCREMENT,
|
| api_key TEXT,
|
| role TEXT,
|
| content TEXT,
|
| ts DATETIME DEFAULT CURRENT_TIMESTAMP
|
| )""")
|
| con.commit()
|
|
|
| init_db()
|
|
|
|
|
| def load_words():
|
| for enc in ("utf-8", "cp1251"):
|
| try:
|
| with open("russian.txt", encoding=enc) as f:
|
| return [w.strip() for w in f if w.strip()]
|
| except:
|
| pass
|
| return ["я", "думаю"]
|
|
|
| WORDS = load_words()
|
|
|
| TEMPLATES = [
|
| "я думаю что {w} {w}",
|
| "{w} это {w}",
|
| "иногда {w}, но {w}",
|
| "мне кажется {w}"
|
| ]
|
|
|
|
|
| def sentence():
|
| tpl = random.choice(TEMPLATES)
|
| for _ in range(tpl.count("{w}")):
|
| tpl = tpl.replace("{w}", random.choice(WORDS), 1)
|
| return tpl.capitalize() + random.choice(CONFIG["endings"])
|
|
|
| def generate_answer():
|
| n = random.randint(CONFIG["min_sentences"], CONFIG["max_sentences"])
|
| return " ".join(sentence() for _ in range(n))
|
|
|
|
|
| def get_api_key():
|
| h = request.headers.get("Authorization", "")
|
| if h.startswith("Bearer "):
|
| return h[7:]
|
| return request.headers.get("X-API-Key")
|
|
|
| def check_key():
|
| key = get_api_key()
|
| if not key:
|
| abort(401, "API key required")
|
|
|
| db = get_db()
|
| cur = db.cursor()
|
|
|
| row = cur.execute(
|
| "SELECT requests, last_day FROM api_keys WHERE key=?",
|
| (key,)
|
| ).fetchone()
|
|
|
| if not row:
|
| abort(403, "Invalid API key")
|
|
|
| today = str(datetime.date.today())
|
| requests, last_day = row
|
|
|
| if last_day != today:
|
| requests = 0
|
|
|
| if requests >= CONFIG["daily_limit"]:
|
| abort(429, "Daily limit exceeded")
|
|
|
| cur.execute(
|
| "UPDATE api_keys SET requests=?, last_day=? WHERE key=?",
|
| (requests + 1, today, key)
|
| )
|
| db.commit()
|
| return key
|
|
|
|
|
| @app.route("/")
|
| def index():
|
| return render_template("index.html")
|
|
|
| @app.route("/health")
|
| def health():
|
| return jsonify({"status": "ok", "version": "1.0.0"})
|
|
|
| @app.route("/config")
|
| def get_config():
|
| return jsonify(CONFIG)
|
|
|
| @app.route("/v1/keys", methods=["POST"])
|
| def create_key():
|
| key = uuid.uuid4().hex
|
| db = get_db()
|
| db.execute(
|
| "INSERT INTO api_keys(key, requests, last_day) VALUES (?,0,'')",
|
| (key,)
|
| )
|
| db.commit()
|
| return jsonify({"api_key": key})
|
|
|
| @app.route("/v1/chat", methods=["POST"])
|
| def chat():
|
| key = check_key()
|
|
|
| data = request.get_json(silent=True) or request.form
|
| msg = data.get("message", "")
|
| if not msg:
|
| return jsonify({"error": "message required"}), 400
|
|
|
| db = get_db()
|
| db.execute(
|
| "INSERT INTO messages(api_key, role, content) VALUES (?,?,?)",
|
| (key, "user", msg)
|
| )
|
|
|
| answer = generate_answer()
|
|
|
| db.execute(
|
| "INSERT INTO messages(api_key, role, content) VALUES (?,?,?)",
|
| (key, "assistant", answer)
|
| )
|
| db.commit()
|
|
|
| return jsonify({"answer": answer})
|
|
|
| @app.route("/v1/chat/completions", methods=["POST"])
|
| def openai_style():
|
| key = check_key()
|
| data = request.get_json(silent=True) or {}
|
|
|
| messages = data.get("messages", [])
|
| user_msg = ""
|
| for m in reversed(messages):
|
| if m.get("role") == "user":
|
| user_msg = m.get("content", "")
|
| break
|
|
|
| answer = generate_answer()
|
|
|
| return jsonify({
|
| "id": "chatcmpl-local",
|
| "object": "chat.completion",
|
| "choices": [{
|
| "index": 0,
|
| "message": {
|
| "role": "assistant",
|
| "content": answer
|
| },
|
| "finish_reason": "stop"
|
| }]
|
| })
|
|
|
| @app.route("/v1/history")
|
| def history():
|
| key = check_key()
|
| rows = get_db().execute(
|
| "SELECT role, content FROM messages WHERE api_key=? ORDER BY id",
|
| (key,)
|
| ).fetchall()
|
| return jsonify(rows)
|
|
|
| if __name__ == "__main__":
|
| app.run(host="0.0.0.0", port=5000, debug=False)
|
|
|