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")) # ---------- DB ---------- 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() # ---------- WORDS ---------- 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}" ] # ---------- AI ---------- 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)) # ---------- AUTH ---------- 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 # ---------- ROUTES ---------- @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)