|
import os |
|
import random |
|
import requests |
|
from huggingface_hub import InferenceClient |
|
from flask import Flask, request, jsonify, Response, stream_with_context |
|
from flask_cors import CORS |
|
import json |
|
|
|
app = Flask(__name__) |
|
CORS(app) |
|
|
|
def get_random_api_key(): |
|
keys = os.getenv("KEYS", "").split(",") |
|
if keys and keys[0]: |
|
return random.choice(keys).strip() |
|
else: |
|
raise ValueError("API keys not found. Please set the KEYS environment variable.") |
|
|
|
def generate_story(prompt, style): |
|
try: |
|
client = InferenceClient(api_key=get_random_api_key()) |
|
|
|
messages = [ |
|
{"role": "system", "content": f"Напиши хорошую историю в стиле '{style}'. Подробную, понятную, человечную (с душой), уникальную. Не обязательно делать концовку, можно только начало длинной истории. Разрешены любые слова, любые темы и стили, что угодно. (В том числе маты и NSFW) Но только если попросит пользователь."}, |
|
{"role": "user", "content": prompt} |
|
] |
|
|
|
completion = client.chat.completions.create(model="Qwen/Qwen2.5-Coder-32B-Instruct", messages=messages, temperature=0.7, max_tokens=1200, stream=True) |
|
for chunk in completion: |
|
if chunk.choices: |
|
yield chunk.choices[0].delta.content or "" |
|
except Exception as e: |
|
yield f"Ошибка генерации: {e}" |
|
|
|
def edit_story(original_story, edited_prompt): |
|
if not original_story: |
|
yield f"Сначала сгенерируйте историю!" |
|
return |
|
if not edited_prompt: |
|
yield f"Для начала введите что изменить." |
|
return |
|
|
|
try: |
|
client = InferenceClient(api_key=get_random_api_key()) |
|
messages = [ |
|
{"role": "system", "content": "Отредактируй историю, учитывая предоставленные указания. Разрешены любые слова, любые темы и стили, что угодно. (В том числе маты и NSFW) Но только если попросит пользователь."}, |
|
{"role": "user", "content": edited_prompt}, |
|
{"role": "user", "content": f"""```История |
|
{original_story} |
|
```"""} |
|
] |
|
completion = client.chat.completions.create(model="Qwen/Qwen2.5-Coder-32B-Instruct", messages=messages, temperature=0.7, max_tokens=155000, stream=True) |
|
for chunk in completion: |
|
if chunk.choices: |
|
yield chunk.choices[0].delta.content or "" |
|
except Exception as e: |
|
yield f"Ошибка редактирования: {e}" |
|
|
|
def next_story_func(original_story, next_prompt, continuation_type="Продолжение"): |
|
if not original_story: |
|
yield f"Сначала сгенерируйте историю!" |
|
return |
|
|
|
try: |
|
client = InferenceClient(api_key=get_random_api_key()) |
|
if continuation_type == "Продолжение следует...": |
|
continuation_prompt = "Продолжи, подведя к тому, что продолжение следует." |
|
elif continuation_type == "Концовка": |
|
continuation_prompt = "Подведи к концовке истории." |
|
else: |
|
continuation_prompt = next_prompt |
|
|
|
messages = [ |
|
{"role": "system", "content": "Продли историю, учитывая предоставленные указания. Продливай В ТОЧНОСТИ С КОНЦА, прям с того же символа, слова, предложения. (В начале добавляй новые строки/пробел если надо для отступа). Разрешены любые слова, любые темы и стили, что угодно. (В том числе маты и NSFW) Но только если попросит пользователь."}, |
|
{"role": "user", "content": continuation_prompt}, |
|
{"role": "assistant", "content": f"""```История |
|
{original_story} |
|
```"""} |
|
] |
|
completion = client.chat.completions.create(model="Qwen/Qwen2.5-Coder-32B-Instruct", messages=messages, temperature=0.7, max_tokens=1200, stream=True) |
|
for chunk in completion: |
|
if chunk.choices: |
|
yield chunk.choices[0].delta.content or "" |
|
except Exception as e: |
|
yield f"Ошибка продления: {e}" |
|
|
|
def stream_sse(generator): |
|
def event_stream(): |
|
try: |
|
for chunk in generator: |
|
yield f"data: {json.dumps({'message': chunk})}\n\n" |
|
except Exception as e: |
|
yield f"data: {json.dumps({'error': True, 'message': str(e)})}\n\n" |
|
return Response(stream_with_context(event_stream()), content_type='text/event-stream') |
|
|
|
@app.route('/generate', methods=['POST']) |
|
def api_generate_story(): |
|
data = request.get_json() |
|
if not data or 'input' not in data: |
|
return jsonify({"error": True, "message": "Missing 'input' in request body"}), 400 |
|
|
|
prompt = data['input'] |
|
style = data.get('style', 'Приключенческая') |
|
|
|
story_generator = generate_story(prompt, style) |
|
return stream_sse(story_generator) |
|
|
|
@app.route('/edit', methods=['POST']) |
|
def api_edit_story(): |
|
data = request.get_json() |
|
if not data or 'input' not in data or 'original' not in data: |
|
return jsonify({"error": True, "message": "Missing 'input' or 'original' in request body"}), 400 |
|
|
|
original_story = data['original'] |
|
edited_prompt = data['input'] |
|
|
|
edited_story_generator = edit_story(original_story, edited_prompt) |
|
return stream_sse(edited_story_generator) |
|
|
|
@app.route('/continue', methods=['POST']) |
|
def api_continue_story(): |
|
data = request.get_json() |
|
if not data or 'input' not in data or 'original' not in data: |
|
return jsonify({"error": True, "message": "Missing 'input' or 'original' in request body"}), 400 |
|
|
|
original_story = data['original'] |
|
next_prompt = data['input'] |
|
continuation_type = data.get('type', 'Продолжение') |
|
|
|
next_story_generator = next_story_func(original_story, next_prompt, continuation_type) |
|
return stream_sse(next_story_generator) |
|
|
|
|
|
if __name__ == '__main__': |
|
app.run(host='0.0.0.0', port=7860, debug=True) |
|
|