phonefern commited on
Commit
6384276
·
1 Parent(s): c2ad725
Files changed (5) hide show
  1. app.py +65 -7
  2. requirements.txt +2 -1
  3. static/index.html +14 -23
  4. static/script.js +35 -11
  5. static/style.css +82 -40
app.py CHANGED
@@ -1,17 +1,75 @@
 
1
  from fastapi import FastAPI
2
  from fastapi.staticfiles import StaticFiles
3
  from fastapi.responses import FileResponse
4
-
5
- from transformers import pipeline
 
 
6
 
7
  app = FastAPI()
8
 
9
- pipe_flan = pipeline("text2text-generation", model="google/flan-t5-small")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
- @app.get("/infer_t5")
12
- def t5(input):
13
- output = pipe_flan(input)
14
- return {"output": output[0]["generated_text"]}
15
 
16
  app.mount("/", StaticFiles(directory="static", html=True), name="static")
17
 
 
1
+ from fastapi import FastAPI, HTTPException
2
  from fastapi import FastAPI
3
  from fastapi.staticfiles import StaticFiles
4
  from fastapi.responses import FileResponse
5
+ import requests
6
+ from transformers import pipeline, AutoModelForSequenceClassification, AutoTokenizer
7
+ import torch
8
+ from pydantic import BaseModel
9
 
10
  app = FastAPI()
11
 
12
+ # Load model directly from Hugging Face Hub
13
+ model_name = "SandboxBhh/sentiment-thai-text-model"
14
+
15
+ try:
16
+ device = 0 if torch.cuda.is_available() else -1 # Check if GPU is available
17
+ # Ensure correct indentation here
18
+ reloaded_pipe = pipeline(
19
+ "text-classification",
20
+ model=model_name,
21
+ tokenizer=model_name,
22
+ device=device,
23
+
24
+ )
25
+
26
+ except Exception as e:
27
+ print(f"Error loading model: {e}")
28
+ reloaded_pipe = None
29
+
30
+ class TextInput(BaseModel):
31
+ text: str
32
+
33
+ def send_line_notification(message, line_token):
34
+ url = "https://notify-api.line.me/api/notify"
35
+ headers = {"Authorization": f"Bearer {line_token}"}
36
+ data = {"message": message}
37
+ response = requests.post(url, headers=headers, data=data)
38
+ return response.status_code
39
+
40
+ def split_message(message, max_length=1000):
41
+ return [message[i:i+max_length] for i in range(0, len(message), max_length)]
42
+
43
+ # Use environment variable for LINE token
44
+ line_token = "C9r65PpEvIvOJSK2xMhgl53WvmOhhnKEOuQq7DsiVJT"
45
+
46
+ @app.post("/classify-text")
47
+ async def classify_text(input: TextInput):
48
+ if reloaded_pipe is None:
49
+ raise HTTPException(status_code=500, detail="Model not loaded")
50
+
51
+ try:
52
+ result = reloaded_pipe(input.text)
53
+ sentiment = result[0]['label'].lower()
54
+ score = result[0]['score']
55
+
56
+ if sentiment == 'neg':
57
+ message = f"[แจ้งเตือน CSI]: ความพึงพอใจของผู้ป่วย \n ข้อความ: {input.text} \n csi score: {score:.2f}"
58
+ message_parts = split_message(message)
59
+
60
+ for i, part in enumerate(message_parts):
61
+ status = send_line_notification(part, line_token)
62
+ if status == 200:
63
+ print(f"ส่งการแจ้งเตือนส่วนที่ {i+1}/{len(message_parts)} ผ่าน LINE สำเร็จ")
64
+ else:
65
+ print(f"การส่งการแจ้งเตือนส่วนที่ {i+1}/{len(message_parts)} ผ่าน LINE ล้มเหลว")
66
+
67
+ return {"result": result, "message": "Negative sentiment detected and notification sent to LINE."}
68
+ else:
69
+ return {"result": result, "message": "Sentiment is not negative. No notification sent."}
70
 
71
+ except Exception as e:
72
+ raise HTTPException(status_code=500, detail=str(e))
 
 
73
 
74
  app.mount("/", StaticFiles(directory="static", html=True), name="static")
75
 
requirements.txt CHANGED
@@ -3,4 +3,5 @@ uvicorn[standard]
3
  transformers
4
  torch
5
  requests
6
- sentencepiece
 
 
3
  transformers
4
  torch
5
  requests
6
+ sentencepiece
7
+ pydantic
static/index.html CHANGED
@@ -3,34 +3,25 @@
3
  <head>
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Fast API 🤗 Space served with Uvicorn</title>
7
  <link rel="stylesheet" href="style.css" />
8
  <script type="module" src="script.js"></script>
9
  </head>
10
  <body>
11
  <main>
12
- <section id="text-gen">
13
- <h1>Text generation using Flan T5</h1>
14
- <p>
15
- Model:
16
- <a
17
- href="https://huggingface.co/google/flan-t5-small"
18
- rel="noreferrer"
19
- target="_blank"
20
- >google/flan-t5-small</a
21
- >
22
- </p>
23
- <form class="text-gen-form">
24
- <label for="text-gen-input">Text prompt</label>
25
- <input
26
- id="text-gen-input"
27
- type="text"
28
- value="English: Translate There are many ducks. German:"
29
- />
30
- <button id="text-gen-submit">Submit</button>
31
- <p class="text-gen-output"></p>
32
- </form>
33
- </section>
34
  </main>
35
  </body>
36
  </html>
 
3
  <head>
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Sentiment Classification</title>
7
  <link rel="stylesheet" href="style.css" />
8
  <script type="module" src="script.js"></script>
9
  </head>
10
  <body>
11
  <main>
12
+ <div class="container">
13
+ <h1>Sentiment Classifier</h1>
14
+ <form id="textForm">
15
+ <textarea id="inputText" placeholder="Enter your message here..."></textarea>
16
+ <button type="submit">Send To Model and Notify To line</button>
17
+ </form>
18
+
19
+ <div class="loader" id="loader"></div>
20
+
21
+ <div class="result success" id="successMessage">ไปแล้ววว..........</div>
22
+ <div class="result error" id="errorMessage">Error message goes here...</div>
23
+ </div>
24
+
 
 
 
 
 
 
 
 
 
25
  </main>
26
  </body>
27
  </html>
static/script.js CHANGED
@@ -1,17 +1,41 @@
1
- const textGenForm = document.querySelector(".text-gen-form");
 
 
 
 
 
2
 
3
- const translateText = async (text) => {
4
- const inferResponse = await fetch(`infer_t5?input=${text}`);
5
- const inferJson = await inferResponse.json();
 
6
 
7
- return inferJson.output;
8
- };
 
9
 
10
- textGenForm.addEventListener("submit", async (event) => {
11
- event.preventDefault();
 
 
 
 
 
 
12
 
13
- const textGenInput = document.getElementById("text-gen-input");
14
- const textGenParagraph = document.querySelector(".text-gen-output");
15
 
16
- textGenParagraph.textContent = await translateText(textGenInput.value);
 
 
 
 
 
 
 
 
 
 
 
 
17
  });
 
1
+ document.getElementById('textForm').addEventListener('submit', async function(event) {
2
+ event.preventDefault();
3
+ const inputText = document.getElementById('inputText').value;
4
+ const loader = document.getElementById('loader');
5
+ const successMessage = document.getElementById('successMessage');
6
+ const errorMessage = document.getElementById('errorMessage');
7
 
8
+ if (!inputText.trim()) {
9
+ alert("Please enter some text!");
10
+ return;
11
+ }
12
 
13
+ loader.style.display = "block";
14
+ successMessage.style.display = "none";
15
+ errorMessage.style.display = "none";
16
 
17
+ try {
18
+ const response = await fetch('/classify-text', {
19
+ method: 'POST',
20
+ headers: {
21
+ 'Content-Type': 'application/json',
22
+ },
23
+ body: JSON.stringify({ text: inputText }),
24
+ });
25
 
26
+ const data = await response.json();
 
27
 
28
+ loader.style.display = "none";
29
+
30
+ if (response.ok) {
31
+ successMessage.style.display = "block";
32
+ successMessage.textContent = data.message;
33
+ } else {
34
+ throw new Error(data.detail || 'An error occurred');
35
+ }
36
+ } catch (error) {
37
+ loader.style.display = "none";
38
+ errorMessage.style.display = "block";
39
+ errorMessage.textContent = error.message;
40
+ }
41
  });
static/style.css CHANGED
@@ -1,45 +1,87 @@
1
  body {
2
- --text: hsl(0 0% 15%);
3
- padding: 2.5rem;
4
- font-family: sans-serif;
5
- color: var(--text);
6
- }
7
-
8
- body.dark-theme {
9
- --text: hsl(0 0% 90%);
10
- background-color: hsl(223 39% 7%);
11
- }
12
-
13
- main {
14
- max-width: 80rem;
15
- text-align: center;
16
- }
17
-
18
- section {
19
  display: flex;
20
- flex-direction: column;
21
  align-items: center;
22
- }
23
-
24
- a {
25
- color: var(--text);
26
- }
27
-
28
- form {
29
- width: 30rem;
30
- margin: 0 auto;
31
- }
32
-
33
- input {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  width: 100%;
35
- }
36
-
37
- button {
 
 
 
38
  cursor: pointer;
39
- }
40
-
41
- .text-gen-output {
42
- min-height: 1.2rem;
43
- margin: 1rem;
44
- border: 0.5px solid grey;
45
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  body {
2
+ font-family: Arial, sans-serif;
3
+ background-color: #f5f5f5;
4
+ padding: 20px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  display: flex;
6
+ justify-content: center;
7
  align-items: center;
8
+ height: 100vh;
9
+ margin: 0;
10
+ }
11
+
12
+ .container {
13
+ background-color: #fff;
14
+ border-radius: 8px;
15
+ box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
16
+ padding: 30px;
17
+ max-width: 500px;
18
+ width: 100%;
19
+ }
20
+
21
+ h1 {
22
+ text-align: center;
23
+ color: #333;
24
+ }
25
+
26
+ textarea {
27
+ width: 100%;
28
+ height: 120px;
29
+ padding: 10px;
30
+ margin-top: 10px;
31
+ font-size: 16px;
32
+ border: 1px solid #ddd;
33
+ border-radius: 4px;
34
+ resize: none;
35
+ }
36
+
37
+ button {
38
  width: 100%;
39
+ padding: 10px;
40
+ background-color: #4CAF50;
41
+ color: white;
42
+ border: none;
43
+ border-radius: 4px;
44
+ font-size: 18px;
45
  cursor: pointer;
46
+ margin-top: 15px;
47
+ }
48
+
49
+ button:hover {
50
+ background-color: #45a049;
51
+ }
52
+
53
+ .result {
54
+ margin-top: 20px;
55
+ padding: 15px;
56
+ border-radius: 4px;
57
+ font-size: 16px;
58
+ display: none;
59
+ }
60
+
61
+ .success {
62
+ background-color: #e7f9e7;
63
+ color: #2d7a2d;
64
+ border: 1px solid #4CAF50;
65
+ }
66
+
67
+ .error {
68
+ background-color: #fdecea;
69
+ color: #a94442;
70
+ border: 1px solid #ebccd1;
71
+ }
72
+
73
+ .loader {
74
+ border: 6px solid #f3f3f3;
75
+ border-radius: 50%;
76
+ border-top: 6px solid #4CAF50;
77
+ width: 40px;
78
+ height: 40px;
79
+ animation: spin 1s linear infinite;
80
+ margin: 20px auto;
81
+ display: none;
82
+ }
83
+
84
+ @keyframes spin {
85
+ 0% { transform: rotate(0deg); }
86
+ 100% { transform: rotate(360deg); }
87
+ }