forked from FardousNayeem/MockAPI
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
143 lines (108 loc) · 3.7 KB
/
app.py
File metadata and controls
143 lines (108 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import os
import json
import re
from flask import Flask, jsonify, render_template, request
from dotenv import load_dotenv
from google import genai
from google.genai import types
load_dotenv()
app = Flask(__name__)
DEFAULT_MODEL = "gemini-2.5-flash"
ALLOWED_MODELS = {"gemini-2.5-flash", "gemini-2.5-flash-preview", "gpt-4o-mini"}
def _extract_json(text: str) -> dict:
t = (text or "").strip()
t = re.sub(r"^```(?:json)?\s*", "", t)
t = re.sub(r"\s*```$", "", t)
if not t.startswith("{"):
m = re.search(r"\{.*\}", t, re.S)
if m:
t = m.group(0)
return json.loads(t)
def _normalize_phone(phone: str | None) -> str | None:
if not phone:
return None
digits = re.sub(r"\D+", "", phone)
if len(digits) == 11 and digits.startswith("1"):
digits = digits[1:]
if len(digits) == 10:
return f"{digits[0:3]}-{digits[3:6]}-{digits[6:10]}"
return phone.strip()
def get_text_and_llm():
payload = request.get_json(silent=True) or {}
text = payload.get("text")
llm = payload.get("llm")
if not text:
text = request.form.get("text")
if not llm:
llm = request.form.get("llm")
if not text:
text = request.args.get("text")
if not llm:
llm = request.args.get("llm")
if not text:
raw = request.get_data(as_text=True) or ""
raw = raw.strip()
if raw and raw[0] != "{":
text = raw
llm = llm or DEFAULT_MODEL
if llm not in ALLOWED_MODELS:
llm = DEFAULT_MODEL
return (text or "").strip(), llm
def call_gemini_extract(text: str, model: str) -> dict:
api_key = os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY")
if not api_key:
raise RuntimeError("Missing GEMINI_API_KEY (or GOOGLE_API_KEY).")
client = genai.Client(api_key=api_key)
prompt = f"""
Extract contact information from the given text.
Return a JSON object with these fields:
- name: The person's full name (string or null)
- email: The email address (string or null)
- phone: The phone number (string or null)
Rules:
- Only extract what is explicitly present. Do NOT guess.
- Return ONLY the JSON object. No markdown. No explanations.
Text:
{text}
""".strip()
resp = client.models.generate_content(
model=model if model.startswith("gemini") else DEFAULT_MODEL,
contents=prompt,
config=types.GenerateContentConfig(
temperature=0,
max_output_tokens=256,
response_mime_type="application/json",
),
)
data = _extract_json(resp.text)
name = data.get("name")
email = data.get("email")
phone = data.get("phone")
name = name.strip() if isinstance(name, str) and name.strip() else None
email = email.strip() if isinstance(email, str) and email.strip() else None
phone = _normalize_phone(phone if isinstance(phone, str) else None)
return {"name": name, "email": email, "phone": phone}
@app.route("/")
def index():
return render_template("index.html", default_model=DEFAULT_MODEL)
@app.route("/health", methods=["GET"])
def health():
return jsonify({"status": "ok"})
@app.route("/parse", methods=["POST"])
def parse():
text, llm = get_text_and_llm()
if not text:
return jsonify({"error": "Field 'text' is required"}), 400
try:
extracted = call_gemini_extract(text, llm)
return jsonify({
"name": extracted["name"],
"email": extracted["email"],
"phone": extracted["phone"],
"found_in_database": False,
"company": None,
})
except Exception as e:
return jsonify({"error": str(e)}), 500
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000, debug=True)