ciyidogan commited on
Commit
16134a9
·
verified ·
1 Parent(s): bde7c31

Upload 15 files

Browse files
Files changed (12) hide show
  1. Dockerfile +25 -25
  2. README.md +10 -10
  3. app.py +80 -1
  4. chat_handler debug.py +136 -0
  5. chat_handler.py +105 -114
  6. inference_test.py +132 -132
  7. intent.py +146 -153
  8. intent_api.py +180 -185
  9. intent_test_runner.py +70 -133
  10. llm_model.py +84 -81
  11. log.py +10 -10
  12. requirements.txt +26 -26
Dockerfile CHANGED
@@ -1,26 +1,26 @@
1
- # === Hugging Face Spaces için temel imaj
2
- FROM python:3.10
3
-
4
- # === Hugging Face Spaces özel dizinleri
5
- RUN mkdir -p /data/chunks /data/tokenized_chunks /data/zip_temp /data/output /app/.cache /app/.torch_cache && chmod -R 777 /data /app
6
-
7
- # === Ortam değişkenleri
8
- ENV HF_HOME=/app/.cache \
9
- HF_DATASETS_CACHE=/app/.cache \
10
- HF_HUB_CACHE=/app/.cache \
11
- TORCH_HOME=/app/.torch_cache
12
-
13
- # PyTorch kernel cache için klasör ve izin tanımı
14
- ENV TORCH_HOME=/app/.torch_cache
15
- RUN mkdir -p /app/.torch_cache && chmod -R 777 /app/.torch_cache
16
-
17
- # === Gereken kütüphaneleri yükle
18
- COPY requirements.txt ./
19
- RUN pip install --no-cache-dir -r requirements.txt
20
-
21
- # === Uygulama dosyalarını kopyala
22
- COPY . /app
23
- WORKDIR /app
24
-
25
- # === Başlangıç komutu
26
  CMD ["python", "app.py"]
 
1
+ # === Hugging Face Spaces için temel imaj
2
+ FROM python:3.10
3
+
4
+ # === Hugging Face Spaces özel dizinleri
5
+ RUN mkdir -p /data/chunks /data/tokenized_chunks /data/zip_temp /data/output /app/.cache /app/.torch_cache && chmod -R 777 /data /app
6
+
7
+ # === Ortam değişkenleri
8
+ ENV HF_HOME=/app/.cache \
9
+ HF_DATASETS_CACHE=/app/.cache \
10
+ HF_HUB_CACHE=/app/.cache \
11
+ TORCH_HOME=/app/.torch_cache
12
+
13
+ # PyTorch kernel cache için klasör ve izin tanımı
14
+ ENV TORCH_HOME=/app/.torch_cache
15
+ RUN mkdir -p /app/.torch_cache && chmod -R 777 /app/.torch_cache
16
+
17
+ # === Gereken kütüphaneleri yükle
18
+ COPY requirements.txt ./
19
+ RUN pip install --no-cache-dir -r requirements.txt
20
+
21
+ # === Uygulama dosyalarını kopyala
22
+ COPY . /app
23
+ WORKDIR /app
24
+
25
+ # === Başlangıç komutu
26
  CMD ["python", "app.py"]
README.md CHANGED
@@ -1,10 +1,10 @@
1
- ---
2
- title: Inference Test
3
- emoji: 👁
4
- colorFrom: yellow
5
- colorTo: pink
6
- sdk: docker
7
- pinned: false
8
- ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
+ ---
2
+ title: Inference Test
3
+ emoji: 👁
4
+ colorFrom: yellow
5
+ colorTo: pink
6
+ sdk: docker
7
+ pinned: false
8
+ ---
9
+
10
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
app.py CHANGED
@@ -1 +1,80 @@
1
- from inference_test import app
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import threading
3
+ import uvicorn
4
+ from fastapi import FastAPI, Request, HTTPException
5
+ from fastapi.responses import JSONResponse
6
+ from service_config import ServiceConfig
7
+ from session import SessionStore
8
+ from llm_model import LLMModel, Message
9
+ from chat_handler import handle_chat
10
+ from log import log
11
+
12
+ # Global nesneler
13
+ service_config = ServiceConfig()
14
+ session_store = SessionStore()
15
+ llm_models = {} # project_name -> LLMModel instance
16
+
17
+ # FastAPI uygulaması
18
+ app = FastAPI()
19
+
20
+ @app.get("/")
21
+ def health():
22
+ return {"status": "ok"}
23
+
24
+ @app.post("/start_chat")
25
+ def start_chat(request: Request):
26
+ project_name = request.query_params.get("project_name")
27
+ if not project_name:
28
+ raise HTTPException(status_code=400, detail="project_name parametresi gereklidir.")
29
+
30
+ if project_name not in service_config.projects:
31
+ raise HTTPException(status_code=400, detail="Geçersiz project_name değeri.")
32
+
33
+ session = session_store.create_session(project_name)
34
+ log(f"🆕 Yeni session başlatıldı: {session.session_id} (proje: {project_name})")
35
+ return {"session_id": session.session_id}
36
+
37
+ @app.post("/reload_config")
38
+ def reload_config():
39
+ try:
40
+ service_config.load(is_reload=True)
41
+ log("🔁 Config reload sonrası tüm projeler için modeller yeniden yükleniyor...")
42
+ for project_name in service_config.projects:
43
+ llm_config = service_config.get_project_llm_config(project_name)
44
+ model_base = llm_config["model_base"]
45
+ model_instance = LLMModel()
46
+ model_instance.setup(model_base)
47
+ llm_models[project_name] = model_instance
48
+ log(f"✅ '{project_name}' için model yüklendi.")
49
+ return {"status": "ok", "message": "Konfigürasyon ve modeller yeniden yüklendi."}
50
+ except Exception as e:
51
+ return JSONResponse(content={"error": str(e)}, status_code=500)
52
+
53
+ @app.post("/chat")
54
+ async def chat(msg: Message, request: Request):
55
+ session_id = request.headers.get("X-Session-ID")
56
+ if not session_id:
57
+ return JSONResponse(content={"error": "Session ID eksik."}, status_code=400)
58
+
59
+ session = session_store.get_session(session_id)
60
+ if not session:
61
+ return JSONResponse(content={"error": "Geçersiz veya süresi dolmuş session."}, status_code=400)
62
+
63
+ project_name = session.project_name
64
+ llm_model = llm_models.get(project_name)
65
+ if llm_model is None:
66
+ return JSONResponse(content={"error": f"{project_name} için model yüklenmemiş."}, status_code=500)
67
+
68
+ return await handle_chat(msg, request, app, service_config, session, llm_model)
69
+
70
+ if __name__ == "__main__":
71
+ log("🌐 Servis başlatılıyor...")
72
+ service_config.load(is_reload=False)
73
+ for project_name in service_config.projects:
74
+ llm_config = service_config.get_project_llm_config(project_name)
75
+ model_base = llm_config["model_base"]
76
+ model_instance = LLMModel()
77
+ model_instance.setup(model_base)
78
+ llm_models[project_name] = model_instance
79
+ log(f"✅ '{project_name}' için model yüklendi.")
80
+ uvicorn.run(app, host="0.0.0.0", port=7860)
chat_handler debug.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import Request
2
+ from fastapi.responses import JSONResponse
3
+ import traceback, random
4
+ from intent import extract_parameters, validate_variable_formats, detect_intent
5
+ from intent_api import execute_intent
6
+ from llm_model import generate_response, get_model, get_tokenizer, Message
7
+ from log import log
8
+
9
+ DEBUG = True
10
+
11
+ async def handle_chat(msg: Message, request: Request, app, s_config):
12
+ user_input = msg.user_input.strip()
13
+ session_id = request.headers.get("X-Session-ID", "demo-session")
14
+
15
+ if not hasattr(app.state, "session_store"):
16
+ app.state.session_store = {}
17
+
18
+ session_store = getattr(app.state, "session_store", {})
19
+ session = session_store.get(session_id, {
20
+ "session_id": session_id,
21
+ "variables": {},
22
+ "auth_tokens": {},
23
+ "last_intent": None,
24
+ "awaiting_variable": None
25
+ })
26
+
27
+ try:
28
+ if get_model() is None or get_tokenizer() is None:
29
+ return {"error": "Model yüklenmedi."}
30
+
31
+ detected_intent, intent_conf = await detect_intent(user_input)
32
+ if DEBUG:
33
+ log(f"🎯 Intent tespiti: {detected_intent}, Confidence: {intent_conf:.2f}")
34
+
35
+ current_intent = session.get("last_intent")
36
+ awaiting_variable = session.get("awaiting_variable")
37
+
38
+ if DEBUG:
39
+ log(f"📦 Session: {session}")
40
+ log(f"🧩 Awaiting: {awaiting_variable}, Last Intent: {current_intent}")
41
+
42
+ if (
43
+ awaiting_variable and
44
+ detected_intent and
45
+ detected_intent != current_intent and
46
+ intent_conf > s_config.INTENT_CONFIDENCE_THRESHOLD
47
+ ):
48
+ log("🧹 Konu değişikliği algılandı → context sıfırlanıyor")
49
+ session["awaiting_variable"] = None
50
+ session["variables"] = {}
51
+ session["last_intent"] = detected_intent
52
+ current_intent = detected_intent
53
+
54
+ intent_is_valid = (
55
+ detected_intent and
56
+ intent_conf > s_config.INTENT_CONFIDENCE_THRESHOLD and
57
+ detected_intent in s_config.INTENT_DEFINITIONS
58
+ )
59
+ if DEBUG:
60
+ log(f"✅ Intent geçerli mi?: {intent_is_valid}")
61
+
62
+ if intent_is_valid:
63
+ session["last_intent"] = detected_intent
64
+ definition = s_config.INTENT_DEFINITIONS[detected_intent]
65
+ pattern_list = definition.get("variables", [])
66
+ data_formats = s_config.DATA_FORMATS
67
+ variable_format_map = definition.get("variable_formats", {})
68
+
69
+ if awaiting_variable:
70
+ extracted = extract_parameters(pattern_list, user_input)
71
+ for p in extracted:
72
+ if p["key"] == awaiting_variable:
73
+ session["variables"][awaiting_variable] = p["value"]
74
+ session["awaiting_variable"] = None
75
+ log(f"✅ Awaiting parametre tamamlandı: {awaiting_variable} = {p['value']}")
76
+ break
77
+
78
+ extracted = extract_parameters(pattern_list, user_input)
79
+ variables = {p["key"]: p["value"] for p in extracted}
80
+ session.setdefault("variables", {}).update(variables)
81
+
82
+ if DEBUG:
83
+ log(f"🧪 Tespit edilen parametreler: {variables}")
84
+
85
+ is_valid, validation_errors = validate_variable_formats(session["variables"], variable_format_map, data_formats)
86
+ if DEBUG:
87
+ log(f"📛 Validasyon hataları: {validation_errors}")
88
+
89
+ if not is_valid:
90
+ session["awaiting_variable"] = list(validation_errors.keys())[0]
91
+ session_store[session_id] = session
92
+ app.state.session_store = session_store
93
+ return {"response": list(validation_errors.values())[0]}
94
+
95
+ expected_vars = list(variable_format_map.keys())
96
+ missing_vars = [v for v in expected_vars if v not in session["variables"]]
97
+ if DEBUG:
98
+ log(f"📌 Beklenen parametreler: {expected_vars}, Eksik: {missing_vars}")
99
+
100
+ if missing_vars:
101
+ session["awaiting_variable"] = missing_vars[0]
102
+ session_store[session_id] = session
103
+ app.state.session_store = session_store
104
+ return {"response": f"Lütfen {missing_vars[0]} bilgisini belirtir misiniz?"}
105
+
106
+ log("🚀 execute_intent() çağrılıyor...")
107
+ result = execute_intent(
108
+ detected_intent,
109
+ user_input,
110
+ session,
111
+ s_config.INTENT_DEFINITIONS,
112
+ s_config.DATA_FORMATS
113
+ )
114
+ if "reply" in result:
115
+ session_store[session_id] = result["session"]
116
+ app.state.session_store = session_store
117
+ return {"reply": result["reply"]}
118
+ elif "errors" in result:
119
+ session_store[session_id] = result["session"]
120
+ app.state.session_store = session_store
121
+ return {"response": list(result["errors"].values())[0]}
122
+ else:
123
+ return {"response": random.choice(s_config.FALLBACK_ANSWERS)}
124
+
125
+ log("🤖 execute_intent çağrılmadı → LLM fallback devrede")
126
+ session["awaiting_variable"] = None
127
+ session["variables"] = {}
128
+ response, response_conf = await generate_response(user_input, s_config)
129
+ if response_conf is not None and response_conf < s_config.LLM_CONFIDENCE_THRESHOLD:
130
+ return {"response": random.choice(s_config.FALLBACK_ANSWERS)}
131
+ return {"response": response}
132
+
133
+ except Exception as e:
134
+ traceback.print_exc()
135
+ return JSONResponse(content={"error": str(e)}, status_code=500)
136
+
chat_handler.py CHANGED
@@ -1,114 +1,105 @@
1
- from fastapi import Request
2
- from fastapi.responses import JSONResponse
3
- import traceback, random
4
- from intent import extract_parameters, validate_variable_formats, detect_intent
5
- from intent_api import execute_intent
6
- from llm_model import generate_response, model, tokenizer, Message
7
- from log import log
8
-
9
- async def handle_chat(msg: Message, request: Request, app, s_config):
10
- user_input = msg.user_input.strip()
11
- session_id = request.headers.get("X-Session-ID", "demo-session")
12
-
13
- if not hasattr(app.state, "session_store"):
14
- app.state.session_store = {}
15
-
16
- session_store = getattr(app.state, "session_store", {})
17
- session = session_store.get(session_id, {
18
- "session_id": session_id,
19
- "variables": {},
20
- "auth_tokens": {},
21
- "last_intent": None,
22
- "awaiting_variable": None
23
- })
24
-
25
- try:
26
- if model is None or tokenizer is None:
27
- return {"error": "Model yüklenmedi."}
28
-
29
- detected_intent, intent_conf = None, 0.0
30
- if s_config.INTENT_MODEL:
31
- detected_intent, intent_conf = await detect_intent(user_input)
32
- log(f"🎯 Intent tespit edildi: {detected_intent} (conf={intent_conf:.2f})")
33
-
34
- current_intent = session.get("last_intent")
35
- awaiting_variable = session.get("awaiting_variable")
36
-
37
- if (
38
- awaiting_variable and
39
- detected_intent and
40
- detected_intent != current_intent and
41
- intent_conf > s_config.INTENT_CONFIDENCE_THRESHOLD
42
- ):
43
- log(f"🧹 Yeni intent: {detected_intent}, önceki: {current_intent} — awaiting sıfırlanıyor.")
44
- session["awaiting_variable"] = None
45
- session["variables"] = {}
46
- session["last_intent"] = detected_intent
47
- current_intent = detected_intent
48
-
49
- if (
50
- detected_intent and
51
- intent_conf > s_config.INTENT_CONFIDENCE_THRESHOLD and
52
- detected_intent in s_config.INTENT_DEFINITIONS
53
- ):
54
- definition = s_config.INTENT_DEFINITIONS[detected_intent]
55
- pattern_list = definition.get("variables", [])
56
- data_formats = s_config.DATA_FORMATS
57
- variable_format_map = definition.get("variable_formats", {})
58
-
59
- if awaiting_variable:
60
- extracted = extract_parameters(pattern_list, user_input)
61
- for p in extracted:
62
- if p["key"] == awaiting_variable:
63
- session["variables"][awaiting_variable] = p["value"]
64
- session["awaiting_variable"] = None
65
- log(f"✅ Awaiting parametre tamamlandı: {awaiting_variable} = {p['value']}")
66
- break
67
-
68
- extracted = extract_parameters(pattern_list, user_input)
69
- variables = {p["key"]: p["value"] for p in extracted}
70
- session.setdefault("variables", {}).update(variables)
71
-
72
- is_valid, validation_errors = validate_variable_formats(session["variables"], variable_format_map, data_formats)
73
- if not is_valid:
74
- session["awaiting_variable"] = list(validation_errors.keys())[0]
75
- session_store[session_id] = session
76
- app.state.session_store = session_store
77
- return {"response": list(validation_errors.values())[0]}
78
-
79
- expected_vars = list(variable_format_map.keys())
80
- missing_vars = [v for v in expected_vars if v not in session["variables"]]
81
- if missing_vars:
82
- session["awaiting_variable"] = missing_vars[0]
83
- session_store[session_id] = session
84
- app.state.session_store = session_store
85
- return {"response": f"Lütfen {missing_vars[0]} bilgisini belirtir misiniz?"}
86
-
87
- result = execute_intent(
88
- detected_intent,
89
- user_input,
90
- session,
91
- s_config.INTENT_DEFINITIONS,
92
- s_config.DATA_FORMATS
93
- )
94
- if "reply" in result:
95
- session_store[session_id] = result["session"]
96
- app.state.session_store = session_store
97
- return {"reply": result["reply"]}
98
- elif "errors" in result:
99
- session_store[session_id] = result["session"]
100
- app.state.session_store = session_store
101
- return {"response": list(result["errors"].values())[0]}
102
- else:
103
- return {"response": random.choice(s_config.FALLBACK_ANSWERS)}
104
-
105
- session["awaiting_variable"] = None
106
- session["variables"] = {}
107
- response, response_conf = await generate_response(user_input, s_config)
108
- if response_conf is not None and response_conf < s_config.LLM_CONFIDENCE_THRESHOLD:
109
- return {"response": random.choice(s_config.FALLBACK_ANSWERS)}
110
- return {"response": response}
111
-
112
- except Exception as e:
113
- traceback.print_exc()
114
- return JSONResponse(content={"error": str(e)}, status_code=500)
 
1
+ from fastapi import Request
2
+ from fastapi.responses import JSONResponse
3
+ import traceback
4
+ import random
5
+ from intent import extract_parameters, validate_variable_formats, detect_intent
6
+ from intent_api import execute_intent
7
+ from log import log
8
+ from llm_model import Message, LLMModel
9
+
10
+ async def handle_chat(msg: Message, request: Request, app, service_config, session, llm_model: LLMModel):
11
+ try:
12
+ user_input = msg.user_input.strip()
13
+ project_name = session.project_name
14
+ project_config = service_config.get_project_llm_config(project_name)
15
+ project_intents = service_config.get_project_intents(project_name)
16
+
17
+ if llm_model.model is None or llm_model.tokenizer is None:
18
+ return {"error": f"{project_name} için model yüklenmedi."}
19
+
20
+ detected_intent, intent_conf = await detect_intent(user_input)
21
+ log(f"🎯 Intent tespit edildi: {detected_intent}, Confidence: {intent_conf:.2f}")
22
+
23
+ current_intent = session.last_intent
24
+ awaiting_variable = session.awaiting_variable
25
+
26
+ if (
27
+ awaiting_variable and
28
+ detected_intent and
29
+ detected_intent != current_intent and
30
+ intent_conf > project_config["intent_confidence_treshold"]
31
+ ):
32
+ log("🧹 Konu değişikliği algılandı context sıfırlanıyor")
33
+ session.awaiting_variable = None
34
+ session.variables = {}
35
+ session.last_intent = detected_intent
36
+ current_intent = detected_intent
37
+
38
+ intent_is_valid = (
39
+ detected_intent and
40
+ intent_conf > project_config["intent_confidence_treshold"] and
41
+ any(i["name"] == detected_intent for i in project_intents)
42
+ )
43
+ log(f" Intent geçerli mi?: {intent_is_valid}")
44
+
45
+ if intent_is_valid:
46
+ session.last_intent = detected_intent
47
+ intent_def = next(i for i in project_intents if i["name"] == detected_intent)
48
+ pattern_list = intent_def.get("variables", [])
49
+ variable_format_map = intent_def.get("variable_formats", {})
50
+ data_formats = service_config.data_formats
51
+
52
+ if awaiting_variable:
53
+ extracted = extract_parameters(pattern_list, user_input)
54
+ for p in extracted:
55
+ if p["key"] == awaiting_variable:
56
+ session.variables[awaiting_variable] = p["value"]
57
+ session.awaiting_variable = None
58
+ log(f"✅ Awaiting parametre tamamlandı: {awaiting_variable} = {p['value']}")
59
+ break
60
+
61
+ extracted = extract_parameters(pattern_list, user_input)
62
+ variables = {p["key"]: p["value"] for p in extracted}
63
+ session.variables.update(variables)
64
+
65
+ is_valid, validation_errors = validate_variable_formats(session.variables, variable_format_map, data_formats)
66
+ log(f"📛 Validasyon hataları: {validation_errors}")
67
+
68
+ if not is_valid:
69
+ session.awaiting_variable = list(validation_errors.keys())[0]
70
+ return {"response": list(validation_errors.values())[0]}
71
+
72
+ expected_vars = list(variable_format_map.keys())
73
+ missing_vars = [v for v in expected_vars if v not in session.variables]
74
+ log(f"📌 Beklenen parametreler: {expected_vars}, Eksik: {missing_vars}")
75
+
76
+ if missing_vars:
77
+ session.awaiting_variable = missing_vars[0]
78
+ return {"response": f"Lütfen {missing_vars[0]} bilgisini belirtir misiniz?"}
79
+
80
+ log("🚀 execute_intent() çağrılıyor...")
81
+ result = execute_intent(
82
+ detected_intent,
83
+ user_input,
84
+ session.__dict__,
85
+ {i["name"]: i for i in project_intents},
86
+ data_formats
87
+ )
88
+ if "reply" in result:
89
+ return {"reply": result["reply"]}
90
+ elif "errors" in result:
91
+ return {"response": list(result["errors"].values())[0]}
92
+ else:
93
+ return {"response": random.choice(project_config["fallback_answers"])}
94
+
95
+ log("🤖 execute_intent çağrılmadı → LLM fallback devrede")
96
+ session.awaiting_variable = None
97
+ session.variables = {}
98
+ response, response_conf = await llm_model.generate_response(user_input, project_config)
99
+ if response_conf is not None and response_conf < project_config["llm_confidence_treshold"]:
100
+ return {"response": random.choice(project_config["fallback_answers"])}
101
+ return {"response": response}
102
+
103
+ except Exception as e:
104
+ traceback.print_exc()
105
+ return JSONResponse(content={"error": str(e)}, status_code=500)
 
 
 
 
 
 
 
 
 
inference_test.py CHANGED
@@ -1,133 +1,133 @@
1
- import os, threading, uvicorn, time, traceback, random, json, asyncio, uuid
2
- from fastapi import FastAPI, Request
3
- from fastapi.responses import HTMLResponse, JSONResponse
4
- from transformers import AutoTokenizer, AutoModelForSequenceClassification
5
- import intent_test_runner
6
- from service_config import ServiceConfig
7
- import intent, intent, llm_model
8
- from log import log
9
- from chat_handler_debug import handle_chat
10
- from llm_model import get_model, get_tokenizer
11
-
12
- s_config = ServiceConfig()
13
- s_config.setup_environment()
14
-
15
- # === FastAPI
16
- app = FastAPI()
17
- chat_history = []
18
-
19
- @app.get("/")
20
- def health():
21
- return {"status": "ok"}
22
-
23
- import uuid # yukarıda zaten eklendiğini varsayıyoruz
24
-
25
- @app.post("/run_tests", status_code=202)
26
- def run_tests():
27
- log("🚦 /run_tests çağrıldı. Testler başlatılıyor...")
28
- threading.Thread(target=intent_test_runner.run_all_tests, daemon=True).start()
29
- return {"status": "running", "message": "Test süreci başlatıldı."}
30
-
31
- @app.get("/start", response_class=HTMLResponse)
32
- def root():
33
- # Yeni session ID üret
34
- session_id = str(uuid.uuid4())
35
- session_info = {
36
- "session_id": session_id,
37
- "variables": {},
38
- "auth_tokens": {},
39
- "last_intent": None,
40
- "awaiting_variable": None
41
- }
42
-
43
- # Session store başlatıldıysa ekle
44
- if not hasattr(app.state, "session_store"):
45
- app.state.session_store = {}
46
- app.state.session_store[session_id] = session_info
47
-
48
- log(f"🌐 /start ile yeni session başlatıldı: {session_id}")
49
-
50
- # HTML + session_id gömülü
51
- return f"""
52
- <html><body>
53
- <h2>Turkcell LLM Chat</h2>
54
- <textarea id='input' rows='4' cols='60'></textarea><br>
55
- <button onclick='send()'>Gönder</button><br><br>
56
- <label>Model Cevabı:</label><br>
57
- <textarea id='output' rows='10' cols='80' readonly style='white-space: pre-wrap;'></textarea>
58
- <script>
59
- const sessionId = "{session_id}";
60
- localStorage.setItem("session_id", sessionId);
61
- async function send() {{
62
- const input = document.getElementById("input").value;
63
- const res = await fetch('/chat', {{
64
- method: 'POST',
65
- headers: {{
66
- 'Content-Type': 'application/json',
67
- 'X-Session-ID': sessionId
68
- }},
69
- body: JSON.stringify({{ user_input: input }})
70
- }});
71
- const data = await res.json();
72
- document.getElementById('output').value = data.reply || data.response || data.error || 'Hata oluştu.';
73
- }}
74
- </script>
75
- </body></html>
76
- """
77
-
78
- @app.post("/start_chat")
79
- def start_chat():
80
- if get_model() is None or get_tokenizer() is None:
81
- return {"error": "Model yüklenmedi."}
82
-
83
- if not hasattr(app.state, "session_store"):
84
- app.state.session_store = {}
85
-
86
- session_id = str(uuid.uuid4())
87
- session_info = {
88
- "session_id": session_id,
89
- "variables": {},
90
- "auth_tokens": {},
91
- "last_intent": None,
92
- "awaiting_variable": None
93
- }
94
- app.state.session_store[session_id] = session_info
95
- log(f"🆕 Yeni session başlatıldı: {session_id}")
96
- return {"session_id": session_id}
97
-
98
- @app.post("/train_intents", status_code=202)
99
- def train_intents(train_input: intent.TrainInput):
100
- log("📥 POST /train_intents çağrıldı.")
101
-
102
- intents = train_input.intents
103
- data_formats = getattr(train_input, "data_formats", [])
104
-
105
- s_config.INTENT_DEFINITIONS = {intent["name"]: intent for intent in intents}
106
- s_config.DATA_FORMATS = data_formats # 🔧 DATA_FORMATS burada set ediliyor
107
-
108
- threading.Thread(
109
- target=lambda: intent.background_training(intents, s_config),
110
- daemon=True
111
- ).start()
112
-
113
- return {"status": "accepted", "message": "Intent eğitimi arka planda başlatıldı."}
114
-
115
- @app.post("/load_intent_model")
116
- def load_intent_model():
117
- try:
118
- intent.INTENT_TOKENIZER = AutoTokenizer.from_pretrained(s_config.INTENT_MODEL_PATH)
119
- intent.INTENT_MODEL = AutoModelForSequenceClassification.from_pretrained(s_config.INTENT_MODEL_PATH)
120
- with open(os.path.join(s_config.INTENT_MODEL_PATH, "label2id.json")) as f:
121
- intent.LABEL2ID = json.load(f)
122
- return {"status": "ok", "message": "Intent modeli yüklendi."}
123
- except Exception as e:
124
- return JSONResponse(content={"error": str(e)}, status_code=500)
125
-
126
- @app.post("/chat")
127
- async def chat(msg: llm_model.Message, request: Request):
128
- return await handle_chat(msg, request, app, s_config)
129
-
130
- threading.Thread(target=llm_model.setup_model, kwargs={"s_config": s_config}, daemon=True).start()
131
- threading.Thread(target=lambda: uvicorn.run(app, host="0.0.0.0", port=7860), daemon=True).start()
132
- while True:
133
  time.sleep(60)
 
1
+ import os, threading, uvicorn, time, traceback, random, json, asyncio, uuid
2
+ from fastapi import FastAPI, Request
3
+ from fastapi.responses import HTMLResponse, JSONResponse
4
+ from transformers import AutoTokenizer, AutoModelForSequenceClassification
5
+ import intent_test_runner
6
+ from service_config import ServiceConfig
7
+ import intent, intent, llm_model
8
+ from log import log
9
+ from chat_handler_debug import handle_chat
10
+ from llm_model import get_model, get_tokenizer
11
+
12
+ s_config = ServiceConfig()
13
+ s_config.setup_environment()
14
+
15
+ # === FastAPI
16
+ app = FastAPI()
17
+ chat_history = []
18
+
19
+ @app.get("/")
20
+ def health():
21
+ return {"status": "ok"}
22
+
23
+ import uuid # yukarıda zaten eklendiğini varsayıyoruz
24
+
25
+ @app.post("/run_tests", status_code=202)
26
+ def run_tests():
27
+ log("🚦 /run_tests çağrıldı. Testler başlatılıyor...")
28
+ threading.Thread(target=intent_test_runner.run_all_tests, daemon=True).start()
29
+ return {"status": "running", "message": "Test süreci başlatıldı."}
30
+
31
+ @app.get("/start", response_class=HTMLResponse)
32
+ def root():
33
+ # Yeni session ID üret
34
+ session_id = str(uuid.uuid4())
35
+ session_info = {
36
+ "session_id": session_id,
37
+ "variables": {},
38
+ "auth_tokens": {},
39
+ "last_intent": None,
40
+ "awaiting_variable": None
41
+ }
42
+
43
+ # Session store başlatıldıysa ekle
44
+ if not hasattr(app.state, "session_store"):
45
+ app.state.session_store = {}
46
+ app.state.session_store[session_id] = session_info
47
+
48
+ log(f"🌐 /start ile yeni session başlatıldı: {session_id}")
49
+
50
+ # HTML + session_id gömülü
51
+ return f"""
52
+ <html><body>
53
+ <h2>Turkcell LLM Chat</h2>
54
+ <textarea id='input' rows='4' cols='60'></textarea><br>
55
+ <button onclick='send()'>Gönder</button><br><br>
56
+ <label>Model Cevabı:</label><br>
57
+ <textarea id='output' rows='10' cols='80' readonly style='white-space: pre-wrap;'></textarea>
58
+ <script>
59
+ const sessionId = "{session_id}";
60
+ localStorage.setItem("session_id", sessionId);
61
+ async function send() {{
62
+ const input = document.getElementById("input").value;
63
+ const res = await fetch('/chat', {{
64
+ method: 'POST',
65
+ headers: {{
66
+ 'Content-Type': 'application/json',
67
+ 'X-Session-ID': sessionId
68
+ }},
69
+ body: JSON.stringify({{ user_input: input }})
70
+ }});
71
+ const data = await res.json();
72
+ document.getElementById('output').value = data.reply || data.response || data.error || 'Hata oluştu.';
73
+ }}
74
+ </script>
75
+ </body></html>
76
+ """
77
+
78
+ @app.post("/start_chat")
79
+ def start_chat():
80
+ if get_model() is None or get_tokenizer() is None:
81
+ return {"error": "Model yüklenmedi."}
82
+
83
+ if not hasattr(app.state, "session_store"):
84
+ app.state.session_store = {}
85
+
86
+ session_id = str(uuid.uuid4())
87
+ session_info = {
88
+ "session_id": session_id,
89
+ "variables": {},
90
+ "auth_tokens": {},
91
+ "last_intent": None,
92
+ "awaiting_variable": None
93
+ }
94
+ app.state.session_store[session_id] = session_info
95
+ log(f"🆕 Yeni session başlatıldı: {session_id}")
96
+ return {"session_id": session_id}
97
+
98
+ @app.post("/train_intents", status_code=202)
99
+ def train_intents(train_input: intent.TrainInput):
100
+ log("📥 POST /train_intents çağrıldı.")
101
+
102
+ intents = train_input.intents
103
+ data_formats = getattr(train_input, "data_formats", [])
104
+
105
+ s_config.INTENT_DEFINITIONS = {intent["name"]: intent for intent in intents}
106
+ s_config.DATA_FORMATS = data_formats # 🔧 DATA_FORMATS burada set ediliyor
107
+
108
+ threading.Thread(
109
+ target=lambda: intent.background_training(intents, s_config),
110
+ daemon=True
111
+ ).start()
112
+
113
+ return {"status": "accepted", "message": "Intent eğitimi arka planda başlatıldı."}
114
+
115
+ @app.post("/load_intent_model")
116
+ def load_intent_model():
117
+ try:
118
+ intent.INTENT_TOKENIZER = AutoTokenizer.from_pretrained(s_config.INTENT_MODEL_PATH)
119
+ intent.INTENT_MODEL = AutoModelForSequenceClassification.from_pretrained(s_config.INTENT_MODEL_PATH)
120
+ with open(os.path.join(s_config.INTENT_MODEL_PATH, "label2id.json")) as f:
121
+ intent.LABEL2ID = json.load(f)
122
+ return {"status": "ok", "message": "Intent modeli yüklendi."}
123
+ except Exception as e:
124
+ return JSONResponse(content={"error": str(e)}, status_code=500)
125
+
126
+ @app.post("/chat")
127
+ async def chat(msg: llm_model.Message, request: Request):
128
+ return await handle_chat(msg, request, app, s_config)
129
+
130
+ threading.Thread(target=llm_model.setup_model, kwargs={"s_config": s_config}, daemon=True).start()
131
+ threading.Thread(target=lambda: uvicorn.run(app, host="0.0.0.0", port=7860), daemon=True).start()
132
+ while True:
133
  time.sleep(60)
intent.py CHANGED
@@ -1,153 +1,146 @@
1
- import os, torch, traceback, json, shutil, re
2
- from datasets import Dataset
3
- from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments, default_data_collator, AutoConfig
4
- from log import log
5
- from pydantic import BaseModel
6
-
7
- INTENT_MODEL = None
8
- INTENT_TOKENIZER = None
9
- LABEL2ID = None
10
-
11
- class TrainInput(BaseModel):
12
- intents: list
13
- data_formats: list = []
14
-
15
- def background_training(intents, s_config):
16
- global INTENT_MODEL, INTENT_TOKENIZER, LABEL2ID
17
- try:
18
- log("🔧 Intent eğitimi başlatıldı...")
19
- texts, labels, label2id = [], [], {}
20
- for idx, intent in enumerate(intents):
21
- label2id[intent["name"]] = idx
22
- for ex in intent["examples"]:
23
- texts.append(ex)
24
- labels.append(idx)
25
-
26
- dataset = Dataset.from_dict({"text": texts, "label": labels})
27
- tokenizer = AutoTokenizer.from_pretrained(s_config.INTENT_MODEL_ID)
28
- config = AutoConfig.from_pretrained(s_config.INTENT_MODEL_ID)
29
- config.problem_type = "single_label_classification"
30
- config.num_labels = len(label2id)
31
- model = AutoModelForSequenceClassification.from_pretrained(s_config.INTENT_MODEL_ID, config=config)
32
-
33
- tokenized_data = {"input_ids": [], "attention_mask": [], "label": []}
34
- for row in dataset:
35
- out = tokenizer(row["text"], truncation=True, padding="max_length", max_length=128)
36
- tokenized_data["input_ids"].append(out["input_ids"])
37
- tokenized_data["attention_mask"].append(out["attention_mask"])
38
- tokenized_data["label"].append(row["label"])
39
-
40
- tokenized = Dataset.from_dict(tokenized_data)
41
- tokenized.set_format(type="torch", columns=["input_ids", "attention_mask", "label"])
42
-
43
- output_dir = "/app/intent_train_output"
44
- os.makedirs(output_dir, exist_ok=True)
45
- trainer = Trainer(
46
- model=model,
47
- args=TrainingArguments(output_dir, per_device_train_batch_size=4, num_train_epochs=3, logging_steps=10, save_strategy="no", report_to=[]),
48
- train_dataset=tokenized,
49
- data_collator=default_data_collator
50
- )
51
- trainer.train()
52
-
53
- # ✅ Başarı raporu üret
54
- log("🔧 Başarı raporu üretiliyor...")
55
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
56
- model.to(device)
57
- input_ids_tensor = tokenized["input_ids"].to(device)
58
- attention_mask_tensor = tokenized["attention_mask"].to(device)
59
-
60
- with torch.no_grad():
61
- outputs = model(input_ids=input_ids_tensor, attention_mask=attention_mask_tensor)
62
- predictions = outputs.logits.argmax(dim=-1).tolist()
63
-
64
- actuals = tokenized["label"]
65
- counts = {}
66
- correct = {}
67
- for pred, actual in zip(predictions, actuals):
68
- intent = list(label2id.keys())[list(label2id.values()).index(actual)]
69
- counts[intent] = counts.get(intent, 0) + 1
70
- if pred == actual:
71
- correct[intent] = correct.get(intent, 0) + 1
72
- for intent, total in counts.items():
73
- accuracy = correct.get(intent, 0) / total
74
- log(f"📊 Intent '{intent}' doğruluk: {accuracy:.2f} — {total} örnek")
75
- if accuracy < s_config.TRAIN_CONFIDENCE_THRESHOLD or total < 5:
76
- log(f"⚠️ Yetersiz performanslı intent: '{intent}' — Doğruluk: {accuracy:.2f}, Örnek: {total}")
77
-
78
- log("📦 Intent modeli eğitimi kaydediliyor...")
79
- if os.path.exists(s_config.INTENT_MODEL_PATH):
80
- shutil.rmtree(s_config.INTENT_MODEL_PATH)
81
- model.save_pretrained(s_config.INTENT_MODEL_PATH)
82
- tokenizer.save_pretrained(s_config.INTENT_MODEL_PATH)
83
- with open(os.path.join(s_config.INTENT_MODEL_PATH, "label2id.json"), "w") as f:
84
- json.dump(label2id, f)
85
-
86
- log(" Intent eğitimi tamamlandı ve model kaydedildi.")
87
-
88
- except Exception as e:
89
- log(f"❌ Intent eğitimi hatası: {e}")
90
- traceback.print_exc()
91
-
92
- async def detect_intent(text):
93
- inputs = INTENT_TOKENIZER(text, return_tensors="pt")
94
- outputs = INTENT_MODEL(**inputs)
95
- probs = torch.nn.functional.softmax(outputs.logits, dim=-1)
96
- confidence, pred_id = torch.max(probs, dim=-1)
97
- id2label = {v: k for k, v in LABEL2ID.items()}
98
- return id2label[pred_id.item()], confidence.item()
99
-
100
- def extract_parameters(variables_list, user_input):
101
- for pattern in variables_list:
102
- regex = re.sub(r"(\w+):\{(.+?)\}", r"(?P<\1>.+?)", pattern)
103
- match = re.match(regex, user_input)
104
- if match:
105
- return [{"key": k, "value": v} for k, v in match.groupdict().items()]
106
- return []
107
-
108
- def resolve_placeholders(text: str, session: dict, variables: dict) -> str:
109
- def replacer(match):
110
- full = match.group(1)
111
- try:
112
- if full.startswith("variables."):
113
- key = full.split(".", 1)[1]
114
- return str(variables.get(key, f"{{{full}}}"))
115
- elif full.startswith("session."):
116
- key = full.split(".", 1)[1]
117
- return str(session.get("variables", {}).get(key, f"{{{full}}}")) # session.variables içinden
118
- elif full.startswith("auth_tokens."):
119
- # auth_tokens.intent.token veya refresh_token
120
- parts = full.split(".")
121
- if len(parts) == 3:
122
- intent, token_type = parts[1], parts[2]
123
- return str(session.get("auth_tokens", {}).get(intent, {}).get(token_type, f"{{{full}}}"))
124
- else:
125
- return f"{{{full}}}"
126
- else:
127
- return f"{{{full}}}" # bilinmeyen yapı
128
- except Exception as e:
129
- return f"{{{full}}}"
130
-
131
- return re.sub(r"\{([^{}]+)\}", replacer, text)
132
-
133
- def validate_variable_formats(variables, variable_format_map, data_formats):
134
- errors = {}
135
- for var_name, format_name in variable_format_map.items():
136
- value = variables.get(var_name)
137
- if value is None:
138
- continue # eksik parametre kontrolü zaten başka yerde yapılacak
139
-
140
- format_def = next((fmt for fmt in data_formats if fmt["name"] == format_name), None)
141
- if not format_def:
142
- continue # tanımsız format
143
-
144
- # valid_options kontrolü
145
- if "valid_options" in format_def:
146
- if value not in format_def["valid_options"]:
147
- errors[var_name] = format_def.get("error_message", f"{var_name} değeri geçersiz.")
148
- # pattern kontrolü
149
- elif "pattern" in format_def:
150
- if not re.fullmatch(format_def["pattern"], value):
151
- errors[var_name] = format_def.get("error_message", f"{var_name} formatı geçersiz.")
152
-
153
- return len(errors) == 0, errors
 
1
+ import os
2
+ import torch
3
+ import json
4
+ import shutil
5
+ import re
6
+ import traceback
7
+ from datasets import Dataset
8
+ from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments, default_data_collator, AutoConfig
9
+ from log import log
10
+
11
+ INTENT_MODELS = {} # project_name -> (model, tokenizer, label2id)
12
+
13
+ async def detect_intent(text):
14
+ # Bu fonksiyon bir örnek; çağırırken ilgili proje için model alınmalı
15
+ raise NotImplementedError("detect_intent çağrısı, proje bazlı model ile yapılmalıdır.")
16
+
17
+ def background_training(project_name, intents, model_id, output_path, confidence_threshold):
18
+ try:
19
+ log(f"🔧 Intent eğitimi başlatıldı (proje: {project_name})")
20
+ texts, labels, label2id = [], [], {}
21
+ for idx, intent in enumerate(intents):
22
+ label2id[intent["name"]] = idx
23
+ for ex in intent["examples"]:
24
+ texts.append(ex)
25
+ labels.append(idx)
26
+
27
+ dataset = Dataset.from_dict({"text": texts, "label": labels})
28
+ tokenizer = AutoTokenizer.from_pretrained(model_id)
29
+ config = AutoConfig.from_pretrained(model_id)
30
+ config.problem_type = "single_label_classification"
31
+ config.num_labels = len(label2id)
32
+ model = AutoModelForSequenceClassification.from_pretrained(model_id, config=config)
33
+
34
+ tokenized_data = {"input_ids": [], "attention_mask": [], "label": []}
35
+ for row in dataset:
36
+ out = tokenizer(row["text"], truncation=True, padding="max_length", max_length=128)
37
+ tokenized_data["input_ids"].append(out["input_ids"])
38
+ tokenized_data["attention_mask"].append(out["attention_mask"])
39
+ tokenized_data["label"].append(row["label"])
40
+
41
+ tokenized = Dataset.from_dict(tokenized_data)
42
+ tokenized.set_format(type="torch", columns=["input_ids", "attention_mask", "label"])
43
+
44
+ if os.path.exists(output_path):
45
+ shutil.rmtree(output_path)
46
+ os.makedirs(output_path, exist_ok=True)
47
+
48
+ trainer = Trainer(
49
+ model=model,
50
+ args=TrainingArguments(output_path, per_device_train_batch_size=4, num_train_epochs=3, logging_steps=10, save_strategy="no", report_to=[]),
51
+ train_dataset=tokenized,
52
+ data_collator=default_data_collator
53
+ )
54
+ trainer.train()
55
+
56
+ # Başarı raporu
57
+ log("🔧 Başarı raporu üretiliyor...")
58
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
59
+ model.to(device)
60
+ input_ids_tensor = torch.tensor(tokenized["input_ids"]).to(device)
61
+ attention_mask_tensor = torch.tensor(tokenized["attention_mask"]).to(device)
62
+
63
+ with torch.no_grad():
64
+ outputs = model(input_ids=input_ids_tensor, attention_mask=attention_mask_tensor)
65
+ predictions = outputs.logits.argmax(dim=-1).tolist()
66
+
67
+ actuals = tokenized["label"]
68
+ counts, correct = {}, {}
69
+ for pred, actual in zip(predictions, actuals):
70
+ intent_name = list(label2id.keys())[list(label2id.values()).index(actual)]
71
+ counts[intent_name] = counts.get(intent_name, 0) + 1
72
+ if pred == actual:
73
+ correct[intent_name] = correct.get(intent_name, 0) + 1
74
+ for intent_name, total in counts.items():
75
+ accuracy = correct.get(intent_name, 0) / total
76
+ log(f"📊 Intent '{intent_name}' doğruluk: {accuracy:.2f} {total} örnek")
77
+ if accuracy < confidence_threshold or total < 5:
78
+ log(f"⚠️ Yetersiz performanslı intent: '{intent_name}' — Doğruluk: {accuracy:.2f}, Örnek: {total}")
79
+
80
+ model.save_pretrained(output_path)
81
+ tokenizer.save_pretrained(output_path)
82
+ with open(os.path.join(output_path, "label2id.json"), "w") as f:
83
+ json.dump(label2id, f)
84
+
85
+ INTENT_MODELS[project_name] = {
86
+ "model": model,
87
+ "tokenizer": tokenizer,
88
+ "label2id": label2id
89
+ }
90
+ log(f"✅ Intent eğitimi tamamlandı ve '{project_name}' modeli yüklendi.")
91
+
92
+ except Exception as e:
93
+ log(f"❌ Intent eğitimi hatası: {e}")
94
+ traceback.print_exc()
95
+
96
+ def extract_parameters(variables_list, user_input):
97
+ for pattern in variables_list:
98
+ regex = re.sub(r"(\w+):\{(.+?)\}", r"(?P<\1>.+?)", pattern)
99
+ match = re.match(regex, user_input)
100
+ if match:
101
+ return [{"key": k, "value": v} for k, v in match.groupdict().items()]
102
+ return []
103
+
104
+ def resolve_placeholders(text: str, session: dict, variables: dict) -> str:
105
+ def replacer(match):
106
+ full = match.group(1)
107
+ try:
108
+ if full.startswith("variables."):
109
+ key = full.split(".", 1)[1]
110
+ return str(variables.get(key, f"{{{full}}}"))
111
+ elif full.startswith("session."):
112
+ key = full.split(".", 1)[1]
113
+ return str(session.get("variables", {}).get(key, f"{{{full}}}"))
114
+ elif full.startswith("auth_tokens."):
115
+ parts = full.split(".")
116
+ if len(parts) == 3:
117
+ intent, token_type = parts[1], parts[2]
118
+ return str(session.get("auth_tokens", {}).get(intent, {}).get(token_type, f"{{{full}}}"))
119
+ else:
120
+ return f"{{{full}}}"
121
+ else:
122
+ return f"{{{full}}}"
123
+ except Exception:
124
+ return f"{{{full}}}"
125
+
126
+ return re.sub(r"\{([^{}]+)\}", replacer, text)
127
+
128
+ def validate_variable_formats(variables, variable_format_map, data_formats):
129
+ errors = {}
130
+ for var_name, format_name in variable_format_map.items():
131
+ value = variables.get(var_name)
132
+ if value is None:
133
+ continue
134
+
135
+ format_def = data_formats.get(format_name)
136
+ if not format_def:
137
+ continue
138
+
139
+ if "valid_options" in format_def:
140
+ if value not in format_def["valid_options"]:
141
+ errors[var_name] = format_def.get("error_message", f"{var_name} değeri geçersiz.")
142
+ elif "pattern" in format_def:
143
+ if not re.fullmatch(format_def["pattern"], value):
144
+ errors[var_name] = format_def.get("error_message", f"{var_name} formatı geçersiz.")
145
+
146
+ return len(errors) == 0, errors
 
 
 
 
 
 
 
intent_api.py CHANGED
@@ -1,186 +1,181 @@
1
- import intent, requests, traceback
2
- from log import log
3
-
4
- def auth_token_handler(intent_name, auth_config, session):
5
- try:
6
- token_info = session.get("auth_tokens", {}).get(intent_name)
7
- if token_info and "token" in token_info:
8
- return token_info["token"], session # Token zaten mevcut
9
-
10
- # Auth token alınmamışsa:
11
- auth_endpoint = auth_config.get("auth_endpoint")
12
- auth_body = auth_config.get("auth_body", {})
13
- token_path = auth_config.get("auth_token_path")
14
-
15
- if not auth_endpoint or not token_path:
16
- raise Exception("auth_endpoint veya token_path tanımsız")
17
-
18
- # Placeholder çözümü (auth_body içinde {session.xxx} varsa çözülür)
19
- resolved_body = {
20
- k: intent.resolve_placeholders(str(v), session, {}) for k, v in auth_body.items()
21
- }
22
-
23
- response = requests.post(auth_endpoint, json=resolved_body, timeout=5)
24
- response.raise_for_status()
25
- json_resp = response.json()
26
-
27
- # Token path (örnek: "token" → json_resp["token"], "data.access_token" → json_resp["data"]["access_token"])
28
- token_parts = token_path.split(".")
29
- token = json_resp
30
- for part in token_parts:
31
- token = token.get(part)
32
- if token is None:
33
- raise Exception(f"Token path çözülemedi: {token_path}")
34
-
35
- # Refresh token varsa
36
- refresh_token = json_resp.get("refresh_token")
37
-
38
- # Session’a kaydet
39
- session.setdefault("auth_tokens", {})[intent_name] = {
40
- "token": token,
41
- "refresh_token": refresh_token
42
- }
43
-
44
- return token, session
45
-
46
- except Exception as e:
47
- log(f"❌ Auth token alınamadı: {e}")
48
- raise e
49
-
50
- def refresh_auth_token(intent_name, auth_config, session):
51
- try:
52
- refresh_endpoint = auth_config.get("auth_refresh_endpoint")
53
- refresh_body = auth_config.get("refresh_body", {})
54
- token_path = auth_config.get("auth_token_path")
55
-
56
- if not refresh_endpoint or not token_path:
57
- raise Exception("Refresh yapılandırması eksik")
58
-
59
- # Refresh token mevcut mu?
60
- refresh_token = session.get("auth_tokens", {}).get(intent_name, {}).get("refresh_token")
61
- if not refresh_token:
62
- raise Exception("Mevcut refresh token bulunamadı")
63
-
64
- # Refresh body içinde placeholder varsa çöz
65
- resolved_body = {
66
- k: intent.resolve_placeholders(str(v), session, {}) for k, v in refresh_body.items()
67
- }
68
-
69
- response = requests.post(refresh_endpoint, json=resolved_body, timeout=5)
70
- response.raise_for_status()
71
- json_resp = response.json()
72
-
73
- # Yeni token çıkar
74
- token_parts = token_path.split(".")
75
- token = json_resp
76
- for part in token_parts:
77
- token = token.get(part)
78
- if token is None:
79
- raise Exception(f"Token path çözülemedi: {token_path}")
80
-
81
- # Yeni refresh_token varsa onu da al
82
- new_refresh_token = json_resp.get("refresh_token", refresh_token)
83
-
84
- # Güncelle
85
- session["auth_tokens"][intent_name] = {
86
- "token": token,
87
- "refresh_token": new_refresh_token
88
- }
89
-
90
- log(f"🔁 Token başarıyla yenilendi: {intent_name}")
91
- return token, session
92
-
93
- except Exception as e:
94
- log(f"❌ Token yenileme başarısız: {e}")
95
- raise e
96
-
97
- def execute_intent(intent_name, user_input, session, intent_definitions, data_formats):
98
- try:
99
- definition = intent_definitions[intent_name]
100
- variables_raw = intent.extract_parameters(definition.get("variables", []), user_input)
101
- variables = {item["key"]: item["value"] for item in variables_raw}
102
-
103
- log(f"🚀 execute_intent('{intent_name}')")
104
- log(f"🔍 Çıkarılan parametreler: {variables}")
105
-
106
- # Validasyon
107
- variable_format_map = definition.get("variable_formats", {})
108
- is_valid, validation_errors = intent.validate_variable_formats(variables, variable_format_map, data_formats)
109
- if not is_valid:
110
- log(f"⚠️ Validasyon hatası: {validation_errors}")
111
- return {
112
- "errors": validation_errors,
113
- "awaiting_variable": list(validation_errors.keys())[0],
114
- "session": session
115
- }
116
-
117
- # Auth
118
- headers = definition["action"].get("headers", [])
119
- body = definition["action"].get("body", {})
120
- method = definition["action"].get("method", "POST")
121
- url = definition["action"]["url"]
122
- timeout = definition["action"].get("timeout", 5)
123
- retry_count = definition["action"].get("retry_count", 0)
124
- auth_config = definition["action"].get("auth", None)
125
- tls = definition["action"].get("tls", {})
126
- verify = tls.get("verify", True)
127
- verify_path = tls.get("ca_bundle") if verify and tls.get("ca_bundle") else verify
128
-
129
- if auth_config:
130
- token, session = auth_token_handler(intent_name, auth_config, session)
131
-
132
- # Header ve Body placeholder çöz
133
- resolved_headers = {
134
- h["key"]: intent.resolve_placeholders(h["value"], session, variables)
135
- for h in headers
136
- }
137
- resolved_body = {
138
- k: intent.resolve_placeholders(str(v), session, variables)
139
- for k, v in body.items()
140
- }
141
-
142
- # API çağrısı
143
- for attempt in range(retry_count + 1):
144
- try:
145
- response = requests.request(
146
- method=method,
147
- url=url,
148
- headers=resolved_headers,
149
- json=resolved_body,
150
- timeout=timeout,
151
- verify=verify_path
152
- )
153
- if response.status_code == 401 and auth_config and attempt < retry_count:
154
- log("🔁 Token expired. Yenileniyor...")
155
- token, session = refresh_auth_token(intent_name, auth_config, session)
156
- continue
157
- response.raise_for_status()
158
- break
159
- except requests.HTTPError as e:
160
- if response.status_code != 401 or attempt == retry_count:
161
- raise e
162
-
163
- log(" API çağrısı başarılı")
164
- json_resp = response.json()
165
-
166
- # Yanıtı parse et
167
- field = definition["action"].get("response_parser", {}).get("field")
168
- rate = json_resp.get(field) if field else json_resp
169
- template = definition["action"].get("reply_template", str(rate))
170
- reply = intent.resolve_placeholders(template, session, {**variables, field: str(rate)})
171
-
172
- # Session güncelle
173
- session.setdefault("variables", {}).update(variables)
174
- session["last_intent"] = intent_name
175
- return {
176
- "reply": reply,
177
- "session": session
178
- }
179
-
180
- except Exception as e:
181
- log(f"❌ execute_intent() hatası: {e}")
182
- traceback.print_exc()
183
- return {
184
- "error": str(e),
185
- "session": session
186
  }
 
1
+ import intent
2
+ import requests
3
+ import traceback
4
+ from log import log
5
+
6
+ def auth_token_handler(api_name, auth_config, session):
7
+ try:
8
+ token_info = session.auth_tokens.get(api_name)
9
+ if token_info and "token" in token_info:
10
+ return token_info["token"], session
11
+
12
+ auth_endpoint = auth_config.get("auth_endpoint")
13
+ auth_body = auth_config.get("auth_body", {})
14
+ token_path = auth_config.get("auth_token_path")
15
+
16
+ if not auth_endpoint or not token_path:
17
+ raise Exception("auth_endpoint veya token_path tanımsız")
18
+
19
+ resolved_body = {
20
+ k: intent.resolve_placeholders(str(v), session.__dict__, session.variables) for k, v in auth_body.items()
21
+ }
22
+
23
+ response = requests.post(auth_endpoint, json=resolved_body, timeout=5)
24
+ response.raise_for_status()
25
+ json_resp = response.json()
26
+
27
+ token_parts = token_path.split(".")
28
+ token = json_resp
29
+ for part in token_parts:
30
+ token = token.get(part)
31
+ if token is None:
32
+ raise Exception(f"Token path çözülemedi: {token_path}")
33
+
34
+ refresh_token = json_resp.get("refresh_token")
35
+ session.auth_tokens[api_name] = {
36
+ "token": token,
37
+ "refresh_token": refresh_token
38
+ }
39
+
40
+ return token, session
41
+
42
+ except Exception as e:
43
+ log(f"❌ Auth token alınamadı: {e}")
44
+ raise e
45
+
46
+ def refresh_auth_token(api_name, auth_config, session):
47
+ try:
48
+ refresh_endpoint = auth_config.get("auth_refresh_endpoint")
49
+ refresh_body = auth_config.get("refresh_body", {})
50
+ token_path = auth_config.get("auth_token_path")
51
+
52
+ if not refresh_endpoint or not token_path:
53
+ raise Exception("Refresh yapılandırması eksik")
54
+
55
+ refresh_token = session.auth_tokens.get(api_name, {}).get("refresh_token")
56
+ if not refresh_token:
57
+ raise Exception("Mevcut refresh token bulunamadı")
58
+
59
+ resolved_body = {
60
+ k: intent.resolve_placeholders(str(v), session.__dict__, session.variables) for k, v in refresh_body.items()
61
+ }
62
+
63
+ response = requests.post(refresh_endpoint, json=resolved_body, timeout=5)
64
+ response.raise_for_status()
65
+ json_resp = response.json()
66
+
67
+ token_parts = token_path.split(".")
68
+ token = json_resp
69
+ for part in token_parts:
70
+ token = token.get(part)
71
+ if token is None:
72
+ raise Exception(f"Token path çözülemedi: {token_path}")
73
+
74
+ new_refresh_token = json_resp.get("refresh_token", refresh_token)
75
+
76
+ session.auth_tokens[api_name] = {
77
+ "token": token,
78
+ "refresh_token": new_refresh_token
79
+ }
80
+
81
+ log(f"🔁 Token başarıyla yenilendi: {api_name}")
82
+ return token, session
83
+
84
+ except Exception as e:
85
+ log(f" Token yenileme başarısız: {e}")
86
+ raise e
87
+
88
+ def execute_intent(intent_name, user_input, session_dict, intent_definitions, data_formats):
89
+ try:
90
+ session = session_dict
91
+ intent_def = intent_definitions[intent_name]
92
+ action_api_name = intent_def.get("action")
93
+
94
+ if not action_api_name:
95
+ raise Exception(f"Intent '{intent_name}' için action tanımı eksik.")
96
+
97
+ api_def = session["service_config"].get_api_config(action_api_name)
98
+ if not api_def:
99
+ raise Exception(f"API '{action_api_name}' tanımı bulunamadı.")
100
+
101
+ variables_raw = intent.extract_parameters(intent_def.get("variables", []), user_input)
102
+ variables = {item["key"]: item["value"] for item in variables_raw}
103
+
104
+ log(f"🚀 execute_intent('{intent_name}')")
105
+ log(f"🔍 Çıkarılan parametreler: {variables}")
106
+
107
+ variable_format_map = intent_def.get("variable_formats", {})
108
+ is_valid, validation_errors = intent.validate_variable_formats(variables, variable_format_map, data_formats)
109
+ if not is_valid:
110
+ log(f"⚠️ Validasyon hatası: {validation_errors}")
111
+ return {
112
+ "errors": validation_errors,
113
+ "awaiting_variable": list(validation_errors.keys())[0],
114
+ "session": session
115
+ }
116
+
117
+ headers = api_def.get("headers", [])
118
+ body = api_def.get("body", {})
119
+ method = api_def.get("method", "POST")
120
+ url = api_def["url"]
121
+ timeout = api_def.get("timeout", 5)
122
+ retry_count = api_def.get("retry_count", 0)
123
+ auth_config = api_def.get("auth")
124
+ tls = api_def.get("tls", {})
125
+ verify = tls.get("verify", True)
126
+ verify_path = tls.get("ca_bundle") if verify and tls.get("ca_bundle") else verify
127
+
128
+ if auth_config:
129
+ token, session = auth_token_handler(action_api_name, auth_config, session)
130
+
131
+ resolved_headers = {
132
+ h["key"]: intent.resolve_placeholders(h["value"], session, variables)
133
+ for h in headers
134
+ }
135
+ resolved_body = {
136
+ k: intent.resolve_placeholders(str(v), session, variables)
137
+ for k, v in body.items()
138
+ }
139
+
140
+ for attempt in range(retry_count + 1):
141
+ try:
142
+ response = requests.request(
143
+ method=method,
144
+ url=url,
145
+ headers=resolved_headers,
146
+ json=resolved_body,
147
+ timeout=timeout,
148
+ verify=verify_path
149
+ )
150
+ if response.status_code == 401 and auth_config and attempt < retry_count:
151
+ log("🔁 Token expired. Yenileniyor...")
152
+ token, session = refresh_auth_token(action_api_name, auth_config, session)
153
+ continue
154
+ response.raise_for_status()
155
+ break
156
+ except requests.HTTPError as e:
157
+ if response.status_code != 401 or attempt == retry_count:
158
+ raise e
159
+
160
+ log("✅ API çağrısı başarılı")
161
+ json_resp = response.json()
162
+
163
+ field = api_def.get("response_parser", {}).get("field")
164
+ value = json_resp.get(field) if field else json_resp
165
+ template = api_def.get("reply_template", str(value))
166
+ reply = intent.resolve_placeholders(template, session, {**variables, field: str(value)})
167
+
168
+ session.setdefault("variables", {}).update(variables)
169
+ session["last_intent"] = intent_name
170
+ return {
171
+ "reply": reply,
172
+ "session": session
173
+ }
174
+
175
+ except Exception as e:
176
+ log(f"❌ execute_intent() hatası: {e}")
177
+ traceback.print_exc()
178
+ return {
179
+ "error": str(e),
180
+ "session": session
 
 
 
 
 
181
  }
intent_test_runner.py CHANGED
@@ -1,133 +1,70 @@
1
- import os, requests, time
2
- from log import log
3
-
4
- BASE_URL = "http://localhost:7860"
5
- MOCK_BASE = os.getenv("MOCK_BASE_URL") # Örnek: https://abc123.ngrok.io
6
-
7
- test_results = []
8
-
9
- def assert_test(name, actual, expected_substring, explanation=None):
10
- if explanation:
11
- log(f"🧪 TEST: {name} → {explanation}")
12
- actual_str = str(actual)
13
- if expected_substring in actual_str:
14
- log(f"[TEST] {name:<45} ✅")
15
- test_results.append((name, True))
16
- else:
17
- log(f"[TEST] {name:<45} ❌ — Beklenen: {expected_substring}, Gelen: {actual_str[:100]}...")
18
- test_results.append((name, False))
19
-
20
- def summarize_tests():
21
- total = len(test_results)
22
- success = sum(1 for _, ok in test_results if ok)
23
- fail = total - success
24
- log("🧾 TEST SONUCU ÖZETİ")
25
- log(f"🔢 Toplam Test : {total}")
26
- log(f" Başarılı : {success}")
27
- log(f" Başarısız : {fail}")
28
-
29
- def wait_for_intent_training(timeout_sec=60):
30
- log("⏳ Intent eğitimi tamamlanıyor mu kontrol ediliyor...")
31
- for _ in range(timeout_sec // 3):
32
- logs = open("/tmp/logs.txt").read() if os.path.exists("/tmp/logs.txt") else ""
33
- if "✅ Intent eğitimi tamamlandı" in logs:
34
- return True
35
- time.sleep(3)
36
- return False
37
-
38
- def run_all_tests():
39
- try:
40
- log("🚀 Test süreci başlatıldı.")
41
- session_id = requests.post(f"{BASE_URL}/start_chat").json().get("session_id")
42
- headers = {"X-Session-ID": session_id}
43
-
44
- # 1. LLM fallback testi
45
- r = requests.post(f"{BASE_URL}/chat", json={"user_input": "zzzzzzzzzzzzz"}, headers=headers)
46
- assert_test("LLM fallback", r.json(), "Bu konuda maalesef")
47
-
48
- # 2. Intent eğitimi (doviz + yol intentleri)
49
- intents = {
50
- "intents": [
51
- {
52
- "name": "doviz-kuru",
53
- "examples": ["dolar kuru nedir", "euro kuru nedir"],
54
- "variables": ["currency:{dolar} kuru nedir", "currency:{euro} kuru nedir"],
55
- "variable_formats": {"currency": "currency_format"},
56
- "action": {
57
- "url": f"{MOCK_BASE}/doviz",
58
- "method": "POST",
59
- "headers": [{"key": "Authorization", "value": "Bearer {auth_tokens.doviz-kuru.token}"}],
60
- "body": {"currency": "{variables.currency}"},
61
- "auth": {
62
- "auth_endpoint": f"{MOCK_BASE}/auth",
63
- "auth_body": {"username": "user", "password": "pass"},
64
- "auth_token_path": "token",
65
- "auth_refresh_endpoint": f"{MOCK_BASE}/refresh",
66
- "refresh_body": {"refresh_token": "{auth_tokens.doviz-kuru.refresh_token}"}
67
- },
68
- "response_parser": {"field": "rate"},
69
- "reply_template": "{variables.currency} kuru şu an {rate} TL."
70
- }
71
- },
72
- {
73
- "name": "yol-durumu",
74
- "examples": ["Ankara'dan İstanbul'a yol durumu"],
75
- "variables": ["from_location:{Ankara} to_location:{İstanbul} yol durumu"],
76
- "action": {
77
- "url": f"{MOCK_BASE}/yol",
78
- "method": "POST",
79
- "headers": [{"key": "Authorization", "value": "Bearer {auth_tokens.yol-durumu.token}"}],
80
- "body": {
81
- "from_location": "{variables.from_location}",
82
- "to_location": "{variables.to_location}"
83
- },
84
- "auth": {
85
- "auth_endpoint": f"{MOCK_BASE}/auth",
86
- "auth_body": {"username": "user", "password": "pass"},
87
- "auth_token_path": "token",
88
- "auth_refresh_endpoint": f"{MOCK_BASE}/refresh",
89
- "refresh_body": {"refresh_token": "{auth_tokens.yol-durumu.refresh_token}"}
90
- },
91
- "response_parser": {"field": "status"},
92
- "reply_template": "{status}"
93
- }
94
- }
95
- ]
96
- }
97
- requests.post(f"{BASE_URL}/train_intents", json=intents)
98
- if not wait_for_intent_training():
99
- assert_test("Intent eğitimi zamanında tamamlandı", "False", "True")
100
- summarize_tests()
101
- return
102
-
103
- r = requests.post(f"{BASE_URL}/load_intent_model")
104
- assert_test("Intent modeli yüklendi", r.json(), "ok")
105
-
106
- # 3. Eksik parametre — doviz-kuru
107
- r = requests.post(f"{BASE_URL}/chat", json={"user_input": "döviz kuru nedir"}, headers=headers)
108
- assert_test("Eksik parametre — currency", r.json(), "Lütfen currency")
109
-
110
- # 4. Parametre tamamlandı — euro
111
- r = requests.post(f"{BASE_URL}/chat", json={"user_input": "euro"}, headers=headers)
112
- assert_test("Parametre tamamlandı — euro", r.json(), "euro kuru şu an")
113
-
114
- # 5. Geçersiz parametre — currency
115
- r = requests.post(f"{BASE_URL}/chat", json={"user_input": "yenidolar kuru nedir"}, headers=headers)
116
- assert_test("Geçersiz parametre — currency", r.json(), "geçerli bir döviz")
117
-
118
- # 6. Eksik parametre — yol durumu
119
- r = requests.post(f"{BASE_URL}/chat", json={"user_input": "Ankara'dan yol durumu"}, headers=headers)
120
- assert_test("Eksik parametre — to_location", r.json(), "Lütfen to_location")
121
-
122
- # 7. Parametre tamamlandı — yol
123
- r = requests.post(f"{BASE_URL}/chat", json={"user_input": "İstanbul"}, headers=headers)
124
- assert_test("Parametre tamamlandı — yol durumu", r.json(), "trafik açık")
125
-
126
- # 8. Konu değişikliği → awaiting reset
127
- r = requests.post(f"{BASE_URL}/chat", json={"user_input": "hava nasıl"}, headers=headers)
128
- assert_test("Konu değişikliği sonrası fallback", r.json(), "Bu konuda maalesef")
129
-
130
- summarize_tests()
131
-
132
- except Exception as e:
133
- log(f"❌ run_all_tests sırasında hata oluştu: {e}")
 
1
+ import os
2
+ import requests
3
+ from log import log
4
+
5
+ BASE_URL = "http://localhost:7860"
6
+ MOCK_BASE = os.getenv("MOCK_BASE_URL") # Örnek: https://abc123.ngrok.io
7
+
8
+ test_results = []
9
+
10
+ def assert_test(name, actual, expected_substring, explanation=None):
11
+ if explanation:
12
+ log(f"🧪 TEST: {name} → {explanation}")
13
+ actual_str = str(actual)
14
+ if expected_substring in actual_str:
15
+ log(f"[TEST] {name:<45} ✅")
16
+ test_results.append((name, True))
17
+ else:
18
+ log(f"[TEST] {name:<45} ❌ — Beklenen: {expected_substring}, Gelen: {actual_str[:100]}...")
19
+ test_results.append((name, False))
20
+
21
+ def summarize_tests():
22
+ total = len(test_results)
23
+ success = sum(1 for _, ok in test_results if ok)
24
+ fail = total - success
25
+ log("🧾 TEST SONUCU ÖZETİ")
26
+ log(f"🔢 Toplam Test : {total}")
27
+ log(f" Başarılı : {success}")
28
+ log(f"❌ Başarısız : {fail}")
29
+
30
+ def run_all_tests():
31
+ try:
32
+ log("🚀 Test süreci başlatıldı.")
33
+ response = requests.post(f"{BASE_URL}/start_chat?project_name=project1")
34
+ session_id = response.json().get("session_id")
35
+ headers = {"X-Session-ID": session_id}
36
+
37
+ # 1. LLM fallback testi (intent bulunamadığında)
38
+ r = requests.post(f"{BASE_URL}/chat", json={"user_input": "bilinmeyen bir soru"}, headers=headers)
39
+ assert_test("LLM fallback", r.json(), "maalesef")
40
+
41
+ # 2. Eksik parametre testi (döviz kuru)
42
+ r = requests.post(f"{BASE_URL}/chat", json={"user_input": "döviz kuru nedir"}, headers=headers)
43
+ assert_test("Eksik parametre — currency", r.json(), "Lütfen currency")
44
+
45
+ # 3. Eksik parametre tamamlanınca tekrar deneme
46
+ r = requests.post(f"{BASE_URL}/chat", json={"user_input": "dolar"}, headers=headers)
47
+ assert_test("Parametre tamamlandı — dolar", r.json(), "dolar kuru şu an")
48
+
49
+ # 4. Geçersiz parametre validasyonu
50
+ r = requests.post(f"{BASE_URL}/chat", json={"user_input": "yenidolar kuru nedir"}, headers=headers)
51
+ assert_test("Geçersiz parametre — currency", r.json(), "geçerli bir döviz")
52
+
53
+ # 5. Konu değişikliği awaiting reset
54
+ r = requests.post(f"{BASE_URL}/chat", json={"user_input": "hava nasıl"}, headers=headers)
55
+ assert_test("Konu değişikliği sonrası fallback", r.json(), "maalesef")
56
+
57
+ # 6. Yol durumu testi (iki parametre eksik veya biri eksik)
58
+ r = requests.post(f"{BASE_URL}/chat", json={"user_input": "yol durumu"}, headers=headers)
59
+ assert_test("Eksik parametre — from_location", r.json(), "Lütfen from_location")
60
+
61
+ r = requests.post(f"{BASE_URL}/chat", json={"user_input": "Ankara"}, headers=headers)
62
+ assert_test("Eksik parametre — to_location", r.json(), "Lütfen to_location")
63
+
64
+ r = requests.post(f"{BASE_URL}/chat", json={"user_input": "İstanbul"}, headers=headers)
65
+ assert_test("Parametre tamamlandı — yol durumu", r.json(), "trafik açık")
66
+
67
+ summarize_tests()
68
+
69
+ except Exception as e:
70
+ log(f"❌ run_all_tests sırasında hata oluştu: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
llm_model.py CHANGED
@@ -1,81 +1,84 @@
1
- import torch, traceback
2
- from transformers import AutoTokenizer, AutoModelForCausalLM, AutoModelForSequenceClassification
3
- from log import log
4
- from pydantic import BaseModel
5
-
6
- _model = None
7
- _tokenizer = None
8
- _eos_token_id = None
9
-
10
- def get_model():
11
- return _model
12
-
13
- def get_tokenizer():
14
- return _tokenizer
15
-
16
- def get_eos_token_id():
17
- return _eos_token_id
18
-
19
- class Message(BaseModel):
20
- user_input: str
21
-
22
- def setup_model(s_config):
23
- global _model, _tokenizer, _eos_token_id
24
- try:
25
- log("🧠 setup_model() başladı")
26
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
27
- log(f"📡 Kullanılan cihaz: {device}")
28
- _tokenizer = AutoTokenizer.from_pretrained(s_config.MODEL_BASE, use_fast=False)
29
- log("📦 Tokenizer yüklendi. Ana model indiriliyor...")
30
- _model = AutoModelForCausalLM.from_pretrained(s_config.MODEL_BASE, torch_dtype=torch.float32).to(device)
31
- log("📦 Ana model indirildi ve yüklendi. eval() çağırılıyor...")
32
- _tokenizer.pad_token = _tokenizer.pad_token or _tokenizer.eos_token
33
- _model.config.pad_token_id = _tokenizer.pad_token_id
34
- _eos_token_id = _tokenizer("<|im_end|>", add_special_tokens=False)["input_ids"][0]
35
- _model.eval()
36
- log(" Ana model eval() çağrıldı")
37
- log(f"📦 Intent modeli indiriliyor: {s_config.INTENT_MODEL_ID}")
38
- _ = AutoTokenizer.from_pretrained(s_config.INTENT_MODEL_ID)
39
- _ = AutoModelForSequenceClassification.from_pretrained(s_config.INTENT_MODEL_ID)
40
- log("✅ Intent modeli önbelleğe alındı.")
41
- log("✔️ Model başarıyla yüklendi ve sohbet için hazır.")
42
- except Exception as e:
43
- log(f"❌ setup_model() hatası: {e}")
44
- traceback.print_exc()
45
-
46
- async def generate_response(text, app_config):
47
- model = get_model()
48
- tokenizer = get_tokenizer()
49
- eos_token_id = get_eos_token_id()
50
-
51
- messages = [{"role": "user", "content": text}]
52
- encodeds = tokenizer.apply_chat_template(messages, return_tensors="pt", add_generation_prompt=True)
53
- input_ids = encodeds.to(model.device)
54
- attention_mask = (input_ids != tokenizer.pad_token_id).long()
55
-
56
- with torch.no_grad():
57
- output = model.generate(
58
- input_ids=input_ids,
59
- attention_mask=attention_mask,
60
- max_new_tokens=128,
61
- do_sample=app_config.USE_SAMPLING,
62
- eos_token_id=eos_token_id,
63
- pad_token_id=tokenizer.pad_token_id,
64
- return_dict_in_generate=True,
65
- output_scores=True
66
- )
67
-
68
- if not app_config.USE_SAMPLING:
69
- scores = torch.stack(output.scores, dim=1)
70
- probs = torch.nn.functional.softmax(scores[0], dim=-1)
71
- top_conf = probs.max().item()
72
- else:
73
- top_conf = None
74
-
75
- decoded = tokenizer.decode(output.sequences[0], skip_special_tokens=True).strip()
76
- for tag in ["assistant", "<|im_start|>assistant"]:
77
- start = decoded.find(tag)
78
- if start != -1:
79
- decoded = decoded[start + len(tag):].strip()
80
- break
81
- return decoded, top_conf
 
 
 
 
1
+ import torch
2
+ import traceback
3
+ from transformers import AutoTokenizer, AutoModelForCausalLM
4
+ from log import log
5
+ from pydantic import BaseModel
6
+
7
+ class Message(BaseModel):
8
+ user_input: str
9
+
10
+ class LLMModel:
11
+ def __init__(self):
12
+ self.model = None
13
+ self.tokenizer = None
14
+ self.eos_token_id = None
15
+
16
+ def setup(self, s_config, project_config):
17
+ try:
18
+ log("🧠 LLMModel setup() başladı")
19
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
20
+ log(f"📡 Kullanılan cihaz: {device}")
21
+
22
+ model_base = project_config["model_base"]
23
+
24
+ if s_config.work_mode == "hfcloud":
25
+ token = s_config.get_auth_token()
26
+ log(f"📦 Hugging Face cloud modeli yükleniyor: {model_base}")
27
+ self.tokenizer = AutoTokenizer.from_pretrained(model_base, use_auth_token=token, use_fast=False)
28
+ self.model = AutoModelForCausalLM.from_pretrained(model_base, use_auth_token=token, torch_dtype=torch.float32).to(device)
29
+
30
+ elif s_config.work_mode == "cloud":
31
+ log(f"📦 Diğer cloud ortamından model indiriliyor: {model_base}")
32
+ self.tokenizer = AutoTokenizer.from_pretrained(model_base, use_fast=False)
33
+ self.model = AutoModelForCausalLM.from_pretrained(model_base, torch_dtype=torch.float32).to(device)
34
+
35
+ elif s_config.work_mode == "on-prem":
36
+ log(f"📦 On-prem model path: {model_base}")
37
+ self.tokenizer = AutoTokenizer.from_pretrained(model_base, use_fast=False)
38
+ self.model = AutoModelForCausalLM.from_pretrained(model_base, torch_dtype=torch.float32).to(device)
39
+
40
+ else:
41
+ raise Exception(f"Bilinmeyen work_mode: {s_config.work_mode}")
42
+
43
+ self.tokenizer.pad_token = self.tokenizer.pad_token or self.tokenizer.eos_token
44
+ self.model.config.pad_token_id = self.tokenizer.pad_token_id
45
+ self.eos_token_id = self.tokenizer("<|im_end|>", add_special_tokens=False)["input_ids"][0]
46
+ self.model.eval()
47
+
48
+ log("✅ LLMModel setup() başarıyla tamamlandı.")
49
+ except Exception as e:
50
+ log(f"❌ LLMModel setup() hatası: {e}")
51
+ traceback.print_exc()
52
+
53
+ async def generate_response(self, text, project_config):
54
+ messages = [{"role": "user", "content": text}]
55
+ encodeds = self.tokenizer.apply_chat_template(messages, return_tensors="pt", add_generation_prompt=True)
56
+ input_ids = encodeds.to(self.model.device)
57
+ attention_mask = (input_ids != self.tokenizer.pad_token_id).long()
58
+
59
+ with torch.no_grad():
60
+ output = self.model.generate(
61
+ input_ids=input_ids,
62
+ attention_mask=attention_mask,
63
+ max_new_tokens=128,
64
+ do_sample=project_config["use_sampling"],
65
+ eos_token_id=self.eos_token_id,
66
+ pad_token_id=self.tokenizer.pad_token_id,
67
+ return_dict_in_generate=True,
68
+ output_scores=True
69
+ )
70
+
71
+ if not project_config["use_sampling"]:
72
+ scores = torch.stack(output.scores, dim=1)
73
+ probs = torch.nn.functional.softmax(scores[0], dim=-1)
74
+ top_conf = probs.max().item()
75
+ else:
76
+ top_conf = None
77
+
78
+ decoded = self.tokenizer.decode(output.sequences[0], skip_special_tokens=True).strip()
79
+ for tag in ["assistant", "<|im_start|>assistant"]:
80
+ start = decoded.find(tag)
81
+ if start != -1:
82
+ decoded = decoded[start + len(tag):].strip()
83
+ break
84
+ return decoded, top_conf
log.py CHANGED
@@ -1,11 +1,11 @@
1
- from datetime import datetime
2
-
3
- def log(message):
4
- timestamp = datetime.now().strftime("%H:%M:%S")
5
- line = f"[{timestamp}] {message}"
6
- print(line, flush=True)
7
- try:
8
- with open("/tmp/logs.txt", "a", encoding="utf-8") as f:
9
- f.write(line + "\n")
10
- except Exception:
11
  pass # dosya erişim hataları sessizce geçilir
 
1
+ from datetime import datetime
2
+
3
+ def log(message):
4
+ timestamp = datetime.now().strftime("%H:%M:%S")
5
+ line = f"[{timestamp}] {message}"
6
+ print(line, flush=True)
7
+ try:
8
+ with open("/tmp/logs.txt", "a", encoding="utf-8") as f:
9
+ f.write(line + "\n")
10
+ except Exception:
11
  pass # dosya erişim hataları sessizce geçilir
requirements.txt CHANGED
@@ -1,27 +1,27 @@
1
- # === FastAPI ve sunucu ===
2
- fastapi==0.110.1
3
- uvicorn==0.29.0
4
-
5
- # === Transformers ve NLP araçları ===
6
- transformers==4.40.1
7
- datasets==2.19.1
8
- peft==0.10.0
9
- accelerate==0.29.3
10
- sentence-transformers==2.6.1
11
- sentencepiece==0.1.99
12
-
13
- # === FAISS ve numpy/pandas ===
14
- faiss-cpu==1.7.4
15
- numpy==1.26.4
16
- pandas==2.2.2
17
-
18
- # === Diğer yardımcılar ===
19
- scikit-learn==1.4.2
20
- torch==2.2.2
21
- tokenizers==0.19.1
22
-
23
- # === Hugging Face Hub entegrasyonu ===
24
- huggingface_hub==0.23.0
25
-
26
- # === Parquet desteği için
27
  pyarrow==15.0.2
 
1
+ # === FastAPI ve sunucu ===
2
+ fastapi==0.110.1
3
+ uvicorn==0.29.0
4
+
5
+ # === Transformers ve NLP araçları ===
6
+ transformers==4.40.1
7
+ datasets==2.19.1
8
+ peft==0.10.0
9
+ accelerate==0.29.3
10
+ sentence-transformers==2.6.1
11
+ sentencepiece==0.1.99
12
+
13
+ # === FAISS ve numpy/pandas ===
14
+ faiss-cpu==1.7.4
15
+ numpy==1.26.4
16
+ pandas==2.2.2
17
+
18
+ # === Diğer yardımcılar ===
19
+ scikit-learn==1.4.2
20
+ torch==2.2.2
21
+ tokenizers==0.19.1
22
+
23
+ # === Hugging Face Hub entegrasyonu ===
24
+ huggingface_hub==0.23.0
25
+
26
+ # === Parquet desteği için
27
  pyarrow==15.0.2