samdak93 commited on
Commit
1b76b5d
·
1 Parent(s): 1bb44c6

this is my qrit api , for personal use

Browse files
Files changed (3) hide show
  1. Dockerfile +18 -0
  2. app.py +159 -0
  3. requirements.txt +4 -0
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python runtime
2
+ FROM python:3.10-slim
3
+
4
+ # Set working directory
5
+ WORKDIR /app
6
+
7
+ # Copy app code
8
+ COPY app.py /app/app.py
9
+ COPY requirements.txt /app/requirements.txt
10
+
11
+ # Install dependencies
12
+ RUN pip install --upgrade pip && pip install -r requirements.txt
13
+
14
+ # Expose the port
15
+ EXPOSE 7860
16
+
17
+ # Start the Flask app
18
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify
2
+ from flask_cors import CORS
3
+ import torch
4
+ from transformers import GPT2Tokenizer, GPT2LMHeadModel
5
+ import os
6
+ import re
7
+ import logging
8
+ from datetime import datetime
9
+
10
+ # Configure logging
11
+ logging.basicConfig(level=logging.INFO)
12
+ logger = logging.getLogger(__name__)
13
+
14
+ app = Flask(__name__)
15
+ CORS(app)
16
+
17
+ # Model loading
18
+ MODEL_PATH = os.environ.get('MODEL_PATH', 'samdak93/qrit-2')
19
+ tokenizer = None
20
+ model = None
21
+ device = None
22
+
23
+ def load_model():
24
+ global tokenizer, model, device
25
+ logger.info(f"Loading model from {MODEL_PATH}")
26
+ try:
27
+ tokenizer = GPT2Tokenizer.from_pretrained(MODEL_PATH)
28
+ model = GPT2LMHeadModel.from_pretrained(MODEL_PATH)
29
+ except Exception as e:
30
+ logger.error(f"Error loading custom model: {e}")
31
+ logger.info("Falling back to default GPT-2")
32
+ tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
33
+ model = GPT2LMHeadModel.from_pretrained("gpt2")
34
+
35
+ tokenizer.pad_token = tokenizer.eos_token
36
+ model.config.pad_token_id = model.config.eos_token_id
37
+
38
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
39
+ model.to(device)
40
+ logger.info(f"Model loaded on device: {device}")
41
+
42
+ def generate_recipe(goal_prompt, max_length=300, temperature=0.7):
43
+ global tokenizer, model, device
44
+ if tokenizer is None or model is None:
45
+ load_model()
46
+
47
+ full_prompt = f"### Goal: {goal_prompt}\n### Recipe: "
48
+ input_ids = tokenizer.encode(full_prompt, return_tensors="pt").to(device)
49
+ attention_mask = torch.ones_like(input_ids).to(device)
50
+
51
+ with torch.no_grad():
52
+ output = model.generate(
53
+ input_ids=input_ids,
54
+ attention_mask=attention_mask,
55
+ max_length=max_length,
56
+ temperature=temperature,
57
+ do_sample=True,
58
+ top_k=50,
59
+ top_p=0.95,
60
+ no_repeat_ngram_size=2,
61
+ pad_token_id=tokenizer.eos_token_id
62
+ )
63
+
64
+ generated_text = tokenizer.decode(output[0], skip_special_tokens=True)
65
+ recipe_part = generated_text[len(full_prompt):]
66
+ if "### Goal:" in recipe_part:
67
+ recipe_part = recipe_part.split("### Goal:")[0].strip()
68
+
69
+ return full_prompt + recipe_part
70
+
71
+ def parse_recipe(recipe_text):
72
+ recipe_data = {
73
+ "title": "",
74
+ "ingredients": [],
75
+ "instructions": [],
76
+ "nutrition": {}
77
+ }
78
+
79
+ title_match = re.search(r"Title: (.*?)(?:\n|$)", recipe_text)
80
+ if title_match:
81
+ recipe_data["title"] = title_match.group(1).strip()
82
+
83
+ ingredients_section = re.search(r"Ingredients:(.*?)Instructions:", recipe_text, re.DOTALL)
84
+ if ingredients_section:
85
+ ingredients_text = ingredients_section.group(1).strip()
86
+ ingredients_list = [item.strip().lstrip('- ') for item in ingredients_text.split('\n') if item.strip()]
87
+ recipe_data["ingredients"] = ingredients_list
88
+
89
+ instructions_section = re.search(r"Instructions:(.*?)(?:Nutrition:|$)", recipe_text, re.DOTALL)
90
+ if instructions_section:
91
+ instructions_text = instructions_section.group(1).strip()
92
+ instructions_list = []
93
+ for line in instructions_text.split('\n'):
94
+ line = line.strip()
95
+ if line:
96
+ line = re.sub(r"^\d+\.\s", "", line)
97
+ instructions_list.append(line.strip())
98
+ recipe_data["instructions"] = instructions_list
99
+
100
+ nutrition_section = re.search(r"Nutrition: (.*?)(?:\n|$)", recipe_text)
101
+ if nutrition_section:
102
+ nutrition_text = nutrition_section.group(1).strip()
103
+ for label in ["calories", "sugar", "protein", "fat"]:
104
+ match = re.search(rf"(\d+)\s*(?:g\s*)?{label}", nutrition_text)
105
+ if match:
106
+ recipe_data["nutrition"][label] = int(match.group(1))
107
+
108
+ return recipe_data
109
+
110
+ @app.route('/', methods=['GET'])
111
+ def home():
112
+ return jsonify({
113
+ "name": "Recipe Generation API",
114
+ "version": "1.0.0",
115
+ "endpoints": {
116
+ "/api/healthcheck": "Check API status",
117
+ "/api/generate": "Generate a recipe",
118
+ "/api/parse": "Parse a recipe text"
119
+ }
120
+ })
121
+
122
+ @app.route('/api/healthcheck', methods=['GET'])
123
+ def healthcheck():
124
+ return jsonify({
125
+ "status": "ok",
126
+ "message": "Recipe API is running",
127
+ "timestamp": str(datetime.now())
128
+ })
129
+
130
+ @app.route('/api/generate', methods=['POST'])
131
+ def api_generate_recipe():
132
+ data = request.json
133
+ if not data or 'goal' not in data:
134
+ return jsonify({"error": "Missing 'goal' parameter"}), 400
135
+
136
+ try:
137
+ goal = data['goal']
138
+ max_length = data.get('max_length', 300)
139
+ temperature = data.get('temperature', 0.7)
140
+ recipe_text = generate_recipe(goal, max_length, temperature)
141
+ return jsonify({"goal": goal, "recipe_text": recipe_text})
142
+ except Exception as e:
143
+ logger.error(f"Error generating recipe: {str(e)}")
144
+ return jsonify({"error": str(e)}), 500
145
+
146
+ @app.route('/api/parse', methods=['POST'])
147
+ def api_parse_recipe():
148
+ data = request.json
149
+ if not data or 'recipe_text' not in data:
150
+ return jsonify({"error": "Missing 'recipe_text' parameter"}), 400
151
+ try:
152
+ return jsonify(parse_recipe(data['recipe_text']))
153
+ except Exception as e:
154
+ return jsonify({"error": str(e)}), 500
155
+
156
+ if __name__ == '__main__':
157
+ load_model()
158
+ port = int(os.environ.get('PORT', 7860))
159
+ app.run(host='0.0.0.0', port=port)
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ flask==3.1.0
2
+ flask_cors==5.0.1
3
+ torch==2.2.2 # Replace with CPU version or GPU depending on your use
4
+ transformers==4.51.3