menikev commited on
Commit
62a43f1
·
verified ·
1 Parent(s): 8f63e26

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +574 -574
main.py CHANGED
@@ -1,575 +1,575 @@
1
- from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory, send_file
2
- from flask_sqlalchemy import SQLAlchemy
3
- from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
4
- from flask_wtf import FlaskForm
5
- from wtforms import StringField, PasswordField, SubmitField
6
- from wtforms.validators import DataRequired, Email, EqualTo
7
- from werkzeug.security import generate_password_hash, check_password_hash
8
- from flask_migrate import Migrate
9
- from datetime import datetime, timezone
10
- import os
11
- from pdf_generator import generate_pdf_report
12
- import io
13
-
14
-
15
- app = Flask(__name__, static_folder='static')
16
- app.config['SECRET_KEY'] = '001'
17
- app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
18
- db = SQLAlchemy(app)
19
- migrate = Migrate(app, db)
20
- login_manager = LoginManager(app)
21
- login_manager.login_view = 'login'
22
-
23
- if os.path.exists('users.db'):
24
- os.remove('users.db')
25
-
26
- with app.app_context():
27
- db.create_all()
28
-
29
- class User(UserMixin, db.Model):
30
- id = db.Column(db.Integer, primary_key=True)
31
- email = db.Column(db.String(120), unique=True, nullable=False)
32
- password_hash = db.Column(db.String(128))
33
-
34
- def set_password(self, password):
35
- self.password_hash = generate_password_hash(password)
36
-
37
- def check_password(self, password):
38
- return check_password_hash(self.password_hash, password)
39
-
40
- @login_manager.user_loader
41
- def load_user(user_id):
42
- return User.query.get(int(user_id))
43
-
44
- class RegistrationForm(FlaskForm):
45
- email = StringField('Email', validators=[DataRequired(), Email()])
46
- password = PasswordField('Password', validators=[DataRequired()])
47
- confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
48
- submit = SubmitField('Register')
49
-
50
- class LoginForm(FlaskForm):
51
- email = StringField('Email', validators=[DataRequired(), Email()])
52
- password = PasswordField('Password', validators=[DataRequired()])
53
- submit = SubmitField('Login')
54
-
55
- class AssessmentQuestion(db.Model):
56
- id = db.Column(db.Integer, primary_key=True)
57
- category = db.Column(db.String(50), nullable=False)
58
- subcategory = db.Column(db.String(50), nullable=False)
59
- text = db.Column(db.String(500), nullable=False)
60
- options = db.Column(db.JSON, nullable=False)
61
- scores = db.Column(db.JSON, nullable=False)
62
- max_score = db.Column(db.Float, nullable=False)
63
-
64
- class Assessment(db.Model):
65
- id = db.Column(db.Integer, primary_key=True)
66
- user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
67
- start_date = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
68
- completion_date = db.Column(db.DateTime)
69
- current_question = db.Column(db.Integer, default=1)
70
- status = db.Column(db.String(20), default='In Progress')
71
- strategy_score = db.Column(db.Float, default=0)
72
- governance_score = db.Column(db.Float, default=0)
73
- data_infrastructure_score = db.Column(db.Float, default=0)
74
- organization_score = db.Column(db.Float, default=0)
75
- total_score = db.Column(db.Float, default=0)
76
- readiness_level = db.Column(db.String(50))
77
-
78
- class Response(db.Model):
79
- id = db.Column(db.Integer, primary_key=True)
80
- assessment_id = db.Column(db.Integer, db.ForeignKey('assessment.id'), nullable=False)
81
- question_id = db.Column(db.Integer, db.ForeignKey('assessment_question.id'), nullable=False)
82
- answer = db.Column(db.String(500))
83
- score = db.Column(db.Float)
84
-
85
- def __init__(self, assessment_id, question_id, answer):
86
- self.assessment_id = assessment_id
87
- self.question_id = question_id
88
- self.answer = answer
89
- question = AssessmentQuestion.query.get(question_id)
90
- if question and question.options:
91
- option_index = question.options.index(answer)
92
- self.score = question.scores[option_index]
93
-
94
- def populate_questions():
95
- questions = [
96
- # Strategy (19 points max)
97
- AssessmentQuestion(
98
- category='Strategy',
99
- subcategory='AI Strategy',
100
- text='Does your organization have a well-defined AI strategy?',
101
- options=["Yes, we have a detailed AI strategy.",
102
- "No, we are currently developing an AI strategy.",
103
- "No, we have not started developing an AI strategy.",
104
- "Unsure"],
105
- scores=[5, 3, 1, 0],
106
- max_score=5
107
- ),
108
- AssessmentQuestion(
109
- category='Strategy',
110
- subcategory='Leadership and Ownership',
111
- text='Is there clear leadership or a dedicated team responsible for the AI strategy?',
112
- options=["Yes, there is a dedicated AI team or leader.",
113
- "No, it is managed in an organic and decentralized manner.",
114
- "Unsure"],
115
- scores=[5, 2, 0],
116
- max_score=5
117
- ),
118
- AssessmentQuestion(
119
- category='Strategy',
120
- subcategory='Impact Measurement',
121
- text='Do you have a process to measure the impact of AI deployment?',
122
- options=["Yes, we have a process and clearly defined metrics.",
123
- "Yes, we have a process but are still working on actual metrics.",
124
- "No, we don’t have a process or metrics but are likely to develop this within 12 months.",
125
- "No, we don’t have a process or metrics and are unlikely to develop this within 12 months.",
126
- "Unsure"],
127
- scores=[5, 4, 2, 1, 0],
128
- max_score=5
129
- ),
130
- AssessmentQuestion(
131
- category='Strategy',
132
- subcategory='Financial Strategy',
133
- text='Has your organization established a financial strategy for sustainable AI funding?',
134
- options=["Yes, both short-term and long-term financial strategies are in place.",
135
- "Yes, only a short-term financial strategy is in place.",
136
- "No, but we are currently developing a financial strategy.",
137
- "No, we have no plans to develop a financial strategy.",
138
- "Unsure"],
139
- scores=[5, 3, 2, 1, 0],
140
- max_score=5
141
- ),
142
- AssessmentQuestion(
143
- category='Strategy',
144
- subcategory='Budget Allocation',
145
- text='How is your organization prioritizing budget allocation for AI deployment compared to other technological initiatives?',
146
- options=["AI deployment is the highest priority with additional budget allocated.",
147
- "AI deployment is given equal priority with some additional funding.",
148
- "AI deployment is important but requires cutting spending in other areas.",
149
- "AI deployment depends on other technical initiatives being in place first.",
150
- "Unsure"],
151
- scores=[5, 4, 3, 2, 0],
152
- max_score=5
153
- ),
154
-
155
- # Governance (17 points max)
156
- AssessmentQuestion(
157
- category='Governance',
158
- subcategory='AI Governance Framework',
159
- text='Does your organization have a clearly defined AI governance framework?',
160
- options=["Yes", "No", "Developing"],
161
- scores=[5, 0, 3],
162
- max_score=5
163
- ),
164
- AssessmentQuestion(
165
- category='Governance',
166
- subcategory='Ethical AI Policies',
167
- text='Are there established policies and procedures for ethical AI development and use?',
168
- options=["Yes", "No", "Developing"],
169
- scores=[5, 0, 3],
170
- max_score=5
171
- ),
172
- AssessmentQuestion(
173
- category='Governance',
174
- subcategory='C-suite Engagement',
175
- text='How engaged is your C-suite with AI implementation issues?',
176
- options=["Excellent", "Very Good", "Good", "Fair", "Poor"],
177
- scores=[5, 4, 3, 2, 1],
178
- max_score=5
179
- ),
180
- AssessmentQuestion(
181
- category='Governance',
182
- subcategory='Resource Allocation',
183
- text='How would you rate the allocation of resources (financial, human, technological) to support AI projects?',
184
- options=["Excellent", "Very Good", "Solid", "Fair", "Poor"],
185
- scores=[5, 4, 3, 2, 1],
186
- max_score=5
187
- ),
188
- AssessmentQuestion(
189
- category='Governance',
190
- subcategory='Performance Metrics',
191
- text='Do you have established metrics and KPIs to measure AI initiatives\' performance and impact?',
192
- options=["Yes", "No"],
193
- scores=[5, 0],
194
- max_score=5
195
- ),
196
- AssessmentQuestion(
197
- category='Governance',
198
- subcategory='Change Management',
199
- text='Have you developed a change management plan to address organizational impacts from AI implementations?',
200
- options=["Yes", "No", "Developing"],
201
- scores=[5, 0, 3],
202
- max_score=5
203
- ),
204
- AssessmentQuestion(
205
- category='Governance',
206
- subcategory='Transparency and Accountability',
207
- text='Are there mechanisms to ensure transparency and accountability in AI decision-making processes?',
208
- options=["Yes", "No"],
209
- scores=[5, 0],
210
- max_score=5
211
- ),
212
- AssessmentQuestion(
213
- category='Governance',
214
- subcategory='Risk Management',
215
- text='How does your organization manage risks associated with AI implementation, such as bias, privacy concerns, and regulatory compliance?',
216
- options=["Excellent", "Solid", "Good", "Fair", "Poor"],
217
- scores=[5, 4, 3, 2, 1],
218
- max_score=5
219
- ),
220
-
221
- # Data & Infrastructure (20 points max)
222
- AssessmentQuestion(
223
- category='Data & Infrastructure',
224
- subcategory='Data Availability',
225
- text='To what extent is your organization’s data structured and available for AI analysis?',
226
- options=["Data is not available.",
227
- "Data is available but with privacy/compliance concerns.",
228
- "Data is mostly prepared with minor access limitations.",
229
- "Data is fully prepared and accessible.",
230
- "Other"],
231
- scores=[0, 2, 3, 5, 0],
232
- max_score=5
233
- ),
234
- AssessmentQuestion(
235
- category='Data & Infrastructure',
236
- subcategory='Data Collection',
237
- text='Do you collect data on your services?',
238
- options=["Yes", "No"],
239
- scores=[5, 0],
240
- max_score=5
241
- ),
242
- AssessmentQuestion(
243
- category='Data & Infrastructure',
244
- subcategory='Data Accuracy',
245
- text='How would you rate the accuracy and reliability of your data?',
246
- options=["Excellent", "Good", "Moderate", "Fair", "Poor"],
247
- scores=[5, 4, 3, 2, 1],
248
- max_score=5
249
- ),
250
- AssessmentQuestion(
251
- category='Data & Infrastructure',
252
- subcategory='Data Up-to-Date',
253
- text='Do you have a mechanism to ensure your data is up-to-date?',
254
- options=["Yes", "No"],
255
- scores=[5, 0],
256
- max_score=5
257
- ),
258
- AssessmentQuestion(
259
- category='Data & Infrastructure',
260
- subcategory='Data Access',
261
- text='How easy is it for authorized personnel to access the data needed for AI analysis?',
262
- options=["Easy", "Somewhat difficult", "Difficult"],
263
- scores=[5, 3, 1],
264
- max_score=5
265
- ),
266
- AssessmentQuestion(
267
- category='Data & Infrastructure',
268
- subcategory='Data Integration',
269
- text='Do you have systems to integrate data from different sources (e.g., CRM, ERP)?',
270
- options=["Yes", "No"],
271
- scores=[5, 0],
272
- max_score=5
273
- ),
274
- AssessmentQuestion(
275
- category='Data & Infrastructure',
276
- subcategory='Infrastructure Performance',
277
- text='How would you rate the performance of your data storage and computing infrastructure?',
278
- options=["Excellent", "Very Good", "Solid", "Fair", "Poor"],
279
- scores=[5, 4, 3, 2, 1],
280
- max_score=5
281
- ),
282
- AssessmentQuestion(
283
- category='Data & Infrastructure',
284
- subcategory='Scalability',
285
- text='How would you rate your infrastructure\'s capacity to scale to accommodate changing AI demands?',
286
- options=["Excellent", "Very Good", "Solid", "Fair", "Poor"],
287
- scores=[5, 4, 3, 2, 1],
288
- max_score=5
289
- ),
290
- AssessmentQuestion(
291
- category='Data & Infrastructure',
292
- subcategory='Cloud Solutions',
293
- text='Have you considered cloud-based solutions for scalability and flexibility?',
294
- options=["Yes", "No"],
295
- scores=[5, 0],
296
- max_score=5
297
- ),
298
- AssessmentQuestion(
299
- category='Data & Infrastructure',
300
- subcategory='Security Policies',
301
- text='Are there policies to ensure data security and privacy?',
302
- options=["Yes", "No"],
303
- scores=[5, 0],
304
- max_score=5
305
- ),
306
-
307
- # Organization (Talent & Culture) (17 points max)
308
- AssessmentQuestion(
309
- category='Organization (Talent & Culture)',
310
- subcategory='Talent Availability',
311
- text='Does your organization have a dedicated team with expertise in AI technologies?',
312
- options=["Yes", "No"],
313
- scores=[5, 0],
314
- max_score=5
315
- ),
316
- AssessmentQuestion(
317
- category='Organization (Talent & Culture)',
318
- subcategory='Team Capacity',
319
- text='How would you rate your team’s capacity to manage and analyze data effectively?',
320
- options=["Excellent", "Very Good", "Solid", "Fair", "Poor"],
321
- scores=[5, 4, 3, 2, 1],
322
- max_score=5
323
- ),
324
- AssessmentQuestion(
325
- category='Organization (Talent & Culture)',
326
- subcategory='Training Programs',
327
- text='Has your company invested in training programs to upskill employees in AI-related competencies?',
328
- options=["Yes, through external vendors.",
329
- "Yes, with comprehensive internal programs.",
330
- "No, but plans to in the future.",
331
- "No, with no plans.",
332
- "Unsure"],
333
- scores=[5, 4, 3, 1, 0],
334
- max_score=5
335
- ),
336
- AssessmentQuestion(
337
- category='Organization (Talent & Culture)',
338
- subcategory='Knowledge Sharing',
339
- text='Does your organization have mechanisms for knowledge sharing and documentation of best practices in AI development?',
340
- options=["Yes", "No"],
341
- scores=[5, 0],
342
- max_score=5
343
- ),
344
- AssessmentQuestion(
345
- category='Organization (Talent & Culture)',
346
- subcategory='Cross-functional Collaboration',
347
- text='Are there opportunities for collaboration between technical teams and domain experts in AI projects?',
348
- options=["Yes", "No"],
349
- scores=[5, 0],
350
- max_score=5
351
- ),
352
- AssessmentQuestion(
353
- category='Organization (Talent & Culture)',
354
- subcategory='Cultural Readiness',
355
- text='How urgently is your organization looking to embrace AI?',
356
- options=["High urgency", "Moderate urgency", "Limited urgency", "No urgency"],
357
- scores=[5, 4, 3, 1],
358
- max_score=5
359
- ),
360
- AssessmentQuestion(
361
- category='Organization (Talent & Culture)',
362
- subcategory='Board Receptiveness',
363
- text='How receptive is your Board to changes brought about by AI?',
364
- options=["High receptiveness", "Moderate receptiveness", "Limited receptiveness", "Not receptive", "Unsure"],
365
- scores=[5, 4, 3, 1, 0],
366
- max_score=5
367
- ),
368
- AssessmentQuestion(
369
- category='Organization (Talent & Culture)',
370
- subcategory='Leadership Receptiveness',
371
- text='How receptive is your Leadership Team to changes brought about by AI?',
372
- options=["High receptiveness", "Moderate receptiveness", "Limited receptiveness", "Not receptive", "Unsure"],
373
- scores=[5, 4, 3, 1, 0],
374
- max_score=5
375
- ),
376
- AssessmentQuestion(
377
- category='Organization (Talent & Culture)',
378
- subcategory='Change Management Plan',
379
- text='Do you have a change management plan in place to address changes brought about by AI?',
380
- options=["Yes", "No", "Developing"],
381
- scores=[5, 0, 3],
382
- max_score=5
383
- ),
384
- AssessmentQuestion(
385
- category='Organization (Talent & Culture)',
386
- subcategory='Employee Receptiveness',
387
- text='How receptive are your employees to changes brought about by AI?',
388
- options=["High receptiveness", "Moderate receptiveness", "Limited receptiveness", "Not receptive", "Unsure"],
389
- scores=[5, 4, 3, 1, 0],
390
- max_score=5
391
- ),
392
- ]
393
- db.session.bulk_save_objects(questions)
394
- db.session.commit()
395
-
396
-
397
- def calculate_score(assessment):
398
- responses = Response.query.filter_by(assessment_id=assessment.id).all()
399
- category_scores = {
400
- 'Strategy': 0,
401
- 'Governance': 0,
402
- 'Data & Infrastructure': 0,
403
- 'Organization (Talent & Culture)': 0
404
- }
405
- category_max_scores = {
406
- 'Strategy': 19,
407
- 'Governance': 17,
408
- 'Data & Infrastructure': 20,
409
- 'Organization (Talent & Culture)': 17
410
- }
411
-
412
- for response in responses:
413
- question = AssessmentQuestion.query.get(response.question_id)
414
- if question and question.options:
415
- option_index = question.options.index(response.answer)
416
- score = question.scores[option_index]
417
- category_scores[question.category] += score
418
-
419
- # Normalize scores to respect maximum categories scores
420
- for category in category_scores:
421
- category_scores[category] = min(category_scores[category],
422
- category_max_scores[category])
423
-
424
- assessment.strategy_score = category_scores['Strategy']
425
- assessment.governance_score = category_scores['Governance']
426
- assessment.data_infrastructure_score = category_scores['Data & Infrastructure']
427
- assessment.organization_score = category_scores['Organization (Talent & Culture)']
428
-
429
- total_score = sum(category_scores.values())
430
- assessment.total_score = total_score
431
-
432
- if total_score <= 21:
433
- assessment.readiness_level = 'AI Novice'
434
- elif total_score <= 43:
435
- assessment.readiness_level = 'AI Ready'
436
- elif total_score <= 65:
437
- assessment.readiness_level = 'AI Proficient'
438
- else:
439
- assessment.readiness_level = 'AI Advanced'
440
-
441
- db.session.commit()
442
-
443
- @app.route('/static/<path:filename>')
444
- def serve_static(filename):
445
- return send_from_directory(app.static_folder, filename)
446
-
447
- @app.route('/')
448
- def home():
449
- return render_template('home.html')
450
-
451
- @app.route('/register', methods=['GET', 'POST'])
452
- def register():
453
- form = RegistrationForm()
454
- if form.validate_on_submit():
455
- user = User.query.filter_by(email=form.email.data).first()
456
- if user:
457
- flash('Email already registered. Please use a different email.', 'danger')
458
- return redirect(url_for('register'))
459
- new_user = User(email=form.email.data)
460
- new_user.set_password(form.password.data)
461
- db.session.add(new_user)
462
- db.session.commit()
463
- flash('Registration successful. Please log in.', 'success')
464
- return redirect(url_for('login'))
465
- return render_template('register.html', form=form)
466
-
467
- @app.route('/login', methods=['GET', 'POST'])
468
- def login():
469
- form = LoginForm()
470
- if form.validate_on_submit():
471
- user = User.query.filter_by(email=form.email.data).first()
472
- if user and user.check_password(form.password.data):
473
- login_user(user)
474
- flash('Login successful.', 'success')
475
- return redirect(url_for('dashboard'))
476
- else:
477
- flash('Invalid email or password.', 'danger')
478
- return render_template('login.html', form=form)
479
-
480
- @app.route('/logout')
481
- @login_required
482
- def logout():
483
- logout_user()
484
- flash('You have been logged out.', 'info')
485
- return redirect(url_for('home'))
486
-
487
- @app.route('/dashboard')
488
- @login_required
489
- def dashboard():
490
- return render_template('dashboard.html')
491
-
492
- @app.route('/start_assessment')
493
- @login_required
494
- def start_assessment():
495
- assessment = Assessment(user_id=current_user.id)
496
- db.session.add(assessment)
497
- db.session.commit()
498
- return redirect(url_for('assessment_question', assessment_id=assessment.id))
499
-
500
- @app.route('/assessment/<int:assessment_id>', methods=['GET', 'POST'])
501
- @login_required
502
- def assessment_question(assessment_id):
503
- assessment = Assessment.query.get_or_404(assessment_id)
504
- if assessment.user_id != current_user.id:
505
- flash('Unauthorized access to assessment', 'danger')
506
- return redirect(url_for('dashboard'))
507
-
508
- questions = AssessmentQuestion.query.all()
509
- current_question_index = assessment.current_question - 1
510
-
511
- if current_question_index >= len(questions):
512
- return redirect(url_for('assessment_complete', assessment_id=assessment_id))
513
-
514
- current_questions = questions[current_question_index:current_question_index+4]
515
-
516
- if request.method == 'POST':
517
- for question in current_questions:
518
- answer = request.form.get(f'question_{question.id}')
519
- if answer:
520
- response = Response(assessment_id=assessment_id, question_id=question.id, answer=answer)
521
- db.session.add(response)
522
- assessment.current_question += len(current_questions)
523
-
524
- db.session.commit()
525
- return redirect(url_for('assessment_question', assessment_id=assessment_id))
526
- return render_template('assessment_questions.html', questions=current_questions, assessment=assessment)
527
-
528
- @app.route('/assessment/<int:assessment_id>/complete')
529
- @login_required
530
- def assessment_complete(assessment_id):
531
- assessment = Assessment.query.get_or_404(assessment_id)
532
- if assessment.user_id != current_user.id:
533
- flash('Unauthorized access to assessment', 'danger')
534
- return redirect(url_for('dashboard'))
535
-
536
- calculate_score(assessment)
537
- assessment.status = 'Complete'
538
- assessment.completion_date = datetime.now(timezone.utc)
539
- db.session.commit()
540
-
541
- return render_template('assessment_complete.html', assessment=assessment, strategy_score=assessment.strategy_score,
542
- governance_score=assessment.governance_score,
543
- data_infrastructure_score=assessment.data_infrastructure_score,
544
- organization_score=assessment.organization_score,
545
- total_score=assessment.total_score,
546
- readiness_level=assessment.readiness_level)
547
-
548
- @app.route('/assessment/<int:assessment_id>/pdf')
549
- @login_required
550
- def generate_pdf(assessment_id):
551
- assessment = Assessment.query.get_or_404(assessment_id)
552
- if assessment.user_id != current_user.id:
553
- flash('Unauthorized access to assessment', 'danger')
554
- return redirect(url_for('dashboard'))
555
-
556
- pdf_buffer = generate_pdf_report(assessment)
557
- pdf_buffer.seek(0)
558
- return send_file(
559
- io.BytesIO(pdf_buffer.getvalue()),
560
- mimetype='application/pdf',
561
- as_attachment=True,
562
- download_name=f'AI_Readiness_Report_{assessment_id}.pdf' # Changed from attachment_filename
563
- )
564
-
565
- with app.app_context():
566
- db.drop_all()
567
- db.create_all()
568
- populate_questions()
569
-
570
- if __name__ == '__main__':
571
- with app.app_context():
572
- db.create_all()
573
- if not AssessmentQuestion.query.first():
574
- populate_questions()
575
  app.run(debug=True)
 
1
+ from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory, send_file
2
+ from flask_sqlalchemy import SQLAlchemy
3
+ from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
4
+ from flask_wtf import FlaskForm
5
+ from wtforms import StringField, PasswordField, SubmitField
6
+ from wtforms.validators import DataRequired, Email, EqualTo
7
+ from werkzeug.security import generate_password_hash, check_password_hash
8
+ from flask_migrate import Migrate
9
+ from datetime import datetime, timezone
10
+ import os
11
+ from pdf_generator import generate_pdf_report
12
+ import io
13
+
14
+
15
+ app = Flask(__name__, static_folder='static')
16
+ app.config['SECRET_KEY'] = '001'
17
+ app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
18
+ db = SQLAlchemy(app)
19
+ migrate = Migrate(app, db)
20
+ login_manager = LoginManager(app)
21
+ login_manager.login_view = 'login'
22
+
23
+ if os.path.exists('users.db'):
24
+ os.remove('users.db')
25
+
26
+ with app.app_context():
27
+ db.create_all()
28
+
29
+ class User(UserMixin, db.Model):
30
+ id = db.Column(db.Integer, primary_key=True)
31
+ email = db.Column(db.String(120), unique=True, nullable=False)
32
+ password_hash = db.Column(db.String(128))
33
+
34
+ def set_password(self, password):
35
+ self.password_hash = generate_password_hash(password)
36
+
37
+ def check_password(self, password):
38
+ return check_password_hash(self.password_hash, password)
39
+
40
+ @login_manager.user_loader
41
+ def load_user(user_id):
42
+ return User.query.get(int(user_id))
43
+
44
+ class RegistrationForm(FlaskForm):
45
+ email = StringField('Email', validators=[DataRequired(), Email()])
46
+ password = PasswordField('Password', validators=[DataRequired()])
47
+ confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
48
+ submit = SubmitField('Register')
49
+
50
+ class LoginForm(FlaskForm):
51
+ email = StringField('Email', validators=[DataRequired(), Email()])
52
+ password = PasswordField('Password', validators=[DataRequired()])
53
+ submit = SubmitField('Login')
54
+
55
+ class AssessmentQuestion(db.Model):
56
+ id = db.Column(db.Integer, primary_key=True)
57
+ category = db.Column(db.String(50), nullable=False)
58
+ subcategory = db.Column(db.String(50), nullable=False)
59
+ text = db.Column(db.String(500), nullable=False)
60
+ options = db.Column(db.JSON, nullable=False)
61
+ scores = db.Column(db.JSON, nullable=False)
62
+ max_score = db.Column(db.Float, nullable=False)
63
+
64
+ class Assessment(db.Model):
65
+ id = db.Column(db.Integer, primary_key=True)
66
+ user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
67
+ start_date = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
68
+ completion_date = db.Column(db.DateTime)
69
+ current_question = db.Column(db.Integer, default=1)
70
+ status = db.Column(db.String(20), default='In Progress')
71
+ strategy_score = db.Column(db.Float, default=0)
72
+ governance_score = db.Column(db.Float, default=0)
73
+ data_infrastructure_score = db.Column(db.Float, default=0)
74
+ organization_score = db.Column(db.Float, default=0)
75
+ total_score = db.Column(db.Float, default=0)
76
+ readiness_level = db.Column(db.String(50))
77
+
78
+ class Response(db.Model):
79
+ id = db.Column(db.Integer, primary_key=True)
80
+ assessment_id = db.Column(db.Integer, db.ForeignKey('assessment.id'), nullable=False)
81
+ question_id = db.Column(db.Integer, db.ForeignKey('assessment_question.id'), nullable=False)
82
+ answer = db.Column(db.String(500))
83
+ score = db.Column(db.Float)
84
+
85
+ def __init__(self, assessment_id, question_id, answer):
86
+ self.assessment_id = assessment_id
87
+ self.question_id = question_id
88
+ self.answer = answer
89
+ question = AssessmentQuestion.query.get(question_id)
90
+ if question and question.options:
91
+ option_index = question.options.index(answer)
92
+ self.score = question.scores[option_index]
93
+
94
+ def populate_questions():
95
+ questions = [
96
+ # Strategy (19 points max)
97
+ AssessmentQuestion(
98
+ category='Strategy',
99
+ subcategory='AI Strategy',
100
+ text='Does your organization have a well-defined AI strategy?',
101
+ options=["Yes, we have a detailed AI strategy.",
102
+ "No, we are currently developing an AI strategy.",
103
+ "No, we have not started developing an AI strategy.",
104
+ "Unsure"],
105
+ scores=[5, 3, 1, 0],
106
+ max_score=5
107
+ ),
108
+ AssessmentQuestion(
109
+ category='Strategy',
110
+ subcategory='Leadership and Ownership',
111
+ text='Is there clear leadership or a dedicated team responsible for the AI strategy?',
112
+ options=["Yes, there is a dedicated AI team or leader.",
113
+ "No, it is managed in an organic and decentralized manner.",
114
+ "Unsure"],
115
+ scores=[5, 2, 0],
116
+ max_score=5
117
+ ),
118
+ AssessmentQuestion(
119
+ category='Strategy',
120
+ subcategory='Impact Measurement',
121
+ text='Do you have a process to measure the impact of AI deployment?',
122
+ options=["Yes, we have a process and clearly defined metrics.",
123
+ "Yes, we have a process but are still working on actual metrics.",
124
+ "No, we don’t have a process or metrics but are likely to develop this within 12 months.",
125
+ "No, we don’t have a process or metrics and are unlikely to develop this within 12 months.",
126
+ "Unsure"],
127
+ scores=[5, 4, 2, 1, 0],
128
+ max_score=5
129
+ ),
130
+ AssessmentQuestion(
131
+ category='Strategy',
132
+ subcategory='Financial Strategy',
133
+ text='Has your organization established a financial strategy for sustainable AI funding?',
134
+ options=["Yes, both short-term and long-term financial strategies are in place.",
135
+ "Yes, only a short-term financial strategy is in place.",
136
+ "No, but we are currently developing a financial strategy.",
137
+ "No, we have no plans to develop a financial strategy.",
138
+ "Unsure"],
139
+ scores=[5, 3, 2, 1, 0],
140
+ max_score=5
141
+ ),
142
+ AssessmentQuestion(
143
+ category='Strategy',
144
+ subcategory='Budget Allocation',
145
+ text='How is your organization prioritizing budget allocation for AI deployment compared to other technological initiatives?',
146
+ options=["AI deployment is the highest priority with additional budget allocated.",
147
+ "AI deployment is given equal priority with some additional funding.",
148
+ "AI deployment is important but requires cutting spending in other areas.",
149
+ "AI deployment depends on other technical initiatives being in place first.",
150
+ "Unsure"],
151
+ scores=[5, 4, 3, 2, 0],
152
+ max_score=5
153
+ ),
154
+
155
+ # Governance (17 points max)
156
+ AssessmentQuestion(
157
+ category='Governance',
158
+ subcategory='AI Governance Framework',
159
+ text='Does your organization have a clearly defined AI governance framework?',
160
+ options=["Yes", "No", "Developing"],
161
+ scores=[5, 0, 3],
162
+ max_score=5
163
+ ),
164
+ AssessmentQuestion(
165
+ category='Governance',
166
+ subcategory='Ethical AI Policies',
167
+ text='Are there established policies and procedures for ethical AI development and use?',
168
+ options=["Yes", "No", "Developing"],
169
+ scores=[5, 0, 3],
170
+ max_score=5
171
+ ),
172
+ AssessmentQuestion(
173
+ category='Governance',
174
+ subcategory='C-suite Engagement',
175
+ text='How engaged is your C-suite with AI implementation issues?',
176
+ options=["Excellent", "Very Good", "Good", "Fair", "Poor"],
177
+ scores=[5, 4, 3, 2, 1],
178
+ max_score=5
179
+ ),
180
+ AssessmentQuestion(
181
+ category='Governance',
182
+ subcategory='Resource Allocation',
183
+ text='How would you rate the allocation of resources (financial, human, technological) to support AI projects?',
184
+ options=["Excellent", "Very Good", "Solid", "Fair", "Poor"],
185
+ scores=[5, 4, 3, 2, 1],
186
+ max_score=5
187
+ ),
188
+ AssessmentQuestion(
189
+ category='Governance',
190
+ subcategory='Performance Metrics',
191
+ text='Do you have established metrics and KPIs to measure AI initiatives\' performance and impact?',
192
+ options=["Yes", "No"],
193
+ scores=[5, 0],
194
+ max_score=5
195
+ ),
196
+ AssessmentQuestion(
197
+ category='Governance',
198
+ subcategory='Change Management',
199
+ text='Have you developed a change management plan to address organizational impacts from AI implementations?',
200
+ options=["Yes", "No", "Developing"],
201
+ scores=[5, 0, 3],
202
+ max_score=5
203
+ ),
204
+ AssessmentQuestion(
205
+ category='Governance',
206
+ subcategory='Transparency and Accountability',
207
+ text='Are there mechanisms to ensure transparency and accountability in AI decision-making processes?',
208
+ options=["Yes", "No"],
209
+ scores=[5, 0],
210
+ max_score=5
211
+ ),
212
+ AssessmentQuestion(
213
+ category='Governance',
214
+ subcategory='Risk Management',
215
+ text='How does your organization manage risks associated with AI implementation, such as bias, privacy concerns, and regulatory compliance?',
216
+ options=["Excellent", "Solid", "Good", "Fair", "Poor"],
217
+ scores=[5, 4, 3, 2, 1],
218
+ max_score=5
219
+ ),
220
+
221
+ # Data & Infrastructure (20 points max)
222
+ AssessmentQuestion(
223
+ category='Data & Infrastructure',
224
+ subcategory='Data Availability',
225
+ text='To what extent is your organization’s data structured and available for AI analysis?',
226
+ options=["Data is not available.",
227
+ "Data is available but with privacy/compliance concerns.",
228
+ "Data is mostly prepared with minor access limitations.",
229
+ "Data is fully prepared and accessible.",
230
+ "Other"],
231
+ scores=[0, 2, 3, 5, 0],
232
+ max_score=5
233
+ ),
234
+ AssessmentQuestion(
235
+ category='Data & Infrastructure',
236
+ subcategory='Data Collection',
237
+ text='Do you collect data on your services?',
238
+ options=["Yes", "No"],
239
+ scores=[5, 0],
240
+ max_score=5
241
+ ),
242
+ AssessmentQuestion(
243
+ category='Data & Infrastructure',
244
+ subcategory='Data Accuracy',
245
+ text='How would you rate the accuracy and reliability of your data?',
246
+ options=["Excellent", "Good", "Moderate", "Fair", "Poor"],
247
+ scores=[5, 4, 3, 2, 1],
248
+ max_score=5
249
+ ),
250
+ AssessmentQuestion(
251
+ category='Data & Infrastructure',
252
+ subcategory='Data Up-to-Date',
253
+ text='Do you have a mechanism to ensure your data is up-to-date?',
254
+ options=["Yes", "No"],
255
+ scores=[5, 0],
256
+ max_score=5
257
+ ),
258
+ AssessmentQuestion(
259
+ category='Data & Infrastructure',
260
+ subcategory='Data Access',
261
+ text='How easy is it for authorized personnel to access the data needed for AI analysis?',
262
+ options=["Easy", "Somewhat difficult", "Difficult"],
263
+ scores=[5, 3, 1],
264
+ max_score=5
265
+ ),
266
+ AssessmentQuestion(
267
+ category='Data & Infrastructure',
268
+ subcategory='Data Integration',
269
+ text='Do you have systems to integrate data from different sources (e.g., CRM, ERP)?',
270
+ options=["Yes", "No"],
271
+ scores=[5, 0],
272
+ max_score=5
273
+ ),
274
+ AssessmentQuestion(
275
+ category='Data & Infrastructure',
276
+ subcategory='Infrastructure Performance',
277
+ text='How would you rate the performance of your data storage and computing infrastructure?',
278
+ options=["Excellent", "Very Good", "Solid", "Fair", "Poor"],
279
+ scores=[5, 4, 3, 2, 1],
280
+ max_score=5
281
+ ),
282
+ AssessmentQuestion(
283
+ category='Data & Infrastructure',
284
+ subcategory='Scalability',
285
+ text='How would you rate your infrastructure\'s capacity to scale to accommodate changing AI demands?',
286
+ options=["Excellent", "Very Good", "Solid", "Fair", "Poor"],
287
+ scores=[5, 4, 3, 2, 1],
288
+ max_score=5
289
+ ),
290
+ AssessmentQuestion(
291
+ category='Data & Infrastructure',
292
+ subcategory='Cloud Solutions',
293
+ text='Have you considered cloud-based solutions for scalability and flexibility?',
294
+ options=["Yes", "No"],
295
+ scores=[5, 0],
296
+ max_score=5
297
+ ),
298
+ AssessmentQuestion(
299
+ category='Data & Infrastructure',
300
+ subcategory='Security Policies',
301
+ text='Are there policies to ensure data security and privacy?',
302
+ options=["Yes", "No"],
303
+ scores=[5, 0],
304
+ max_score=5
305
+ ),
306
+
307
+ # Organization (Talent & Culture) (17 points max)
308
+ AssessmentQuestion(
309
+ category='Organization (Talent & Culture)',
310
+ subcategory='Talent Availability',
311
+ text='Does your organization have a dedicated team with expertise in AI technologies?',
312
+ options=["Yes", "No"],
313
+ scores=[5, 0],
314
+ max_score=5
315
+ ),
316
+ AssessmentQuestion(
317
+ category='Organization (Talent & Culture)',
318
+ subcategory='Team Capacity',
319
+ text='How would you rate your team’s capacity to manage and analyze data effectively?',
320
+ options=["Excellent", "Very Good", "Solid", "Fair", "Poor"],
321
+ scores=[5, 4, 3, 2, 1],
322
+ max_score=5
323
+ ),
324
+ AssessmentQuestion(
325
+ category='Organization (Talent & Culture)',
326
+ subcategory='Training Programs',
327
+ text='Has your company invested in training programs to upskill employees in AI-related competencies?',
328
+ options=["Yes, through external vendors.",
329
+ "Yes, with comprehensive internal programs.",
330
+ "No, but plans to in the future.",
331
+ "No, with no plans.",
332
+ "Unsure"],
333
+ scores=[5, 4, 3, 1, 0],
334
+ max_score=5
335
+ ),
336
+ AssessmentQuestion(
337
+ category='Organization (Talent & Culture)',
338
+ subcategory='Knowledge Sharing',
339
+ text='Does your organization have mechanisms for knowledge sharing and documentation of best practices in AI development?',
340
+ options=["Yes", "No"],
341
+ scores=[5, 0],
342
+ max_score=5
343
+ ),
344
+ AssessmentQuestion(
345
+ category='Organization (Talent & Culture)',
346
+ subcategory='Cross-functional Collaboration',
347
+ text='Are there opportunities for collaboration between technical teams and domain experts in AI projects?',
348
+ options=["Yes", "No"],
349
+ scores=[5, 0],
350
+ max_score=5
351
+ ),
352
+ AssessmentQuestion(
353
+ category='Organization (Talent & Culture)',
354
+ subcategory='Cultural Readiness',
355
+ text='How urgently is your organization looking to embrace AI?',
356
+ options=["High urgency", "Moderate urgency", "Limited urgency", "No urgency"],
357
+ scores=[5, 4, 3, 1],
358
+ max_score=5
359
+ ),
360
+ AssessmentQuestion(
361
+ category='Organization (Talent & Culture)',
362
+ subcategory='Board Receptiveness',
363
+ text='How receptive is your Board to changes brought about by AI?',
364
+ options=["High receptiveness", "Moderate receptiveness", "Limited receptiveness", "Not receptive", "Unsure"],
365
+ scores=[5, 4, 3, 1, 0],
366
+ max_score=5
367
+ ),
368
+ AssessmentQuestion(
369
+ category='Organization (Talent & Culture)',
370
+ subcategory='Leadership Receptiveness',
371
+ text='How receptive is your Leadership Team to changes brought about by AI?',
372
+ options=["High receptiveness", "Moderate receptiveness", "Limited receptiveness", "Not receptive", "Unsure"],
373
+ scores=[5, 4, 3, 1, 0],
374
+ max_score=5
375
+ ),
376
+ AssessmentQuestion(
377
+ category='Organization (Talent & Culture)',
378
+ subcategory='Change Management Plan',
379
+ text='Do you have a change management plan in place to address changes brought about by AI?',
380
+ options=["Yes", "No", "Developing"],
381
+ scores=[5, 0, 3],
382
+ max_score=5
383
+ ),
384
+ AssessmentQuestion(
385
+ category='Organization (Talent & Culture)',
386
+ subcategory='Employee Receptiveness',
387
+ text='How receptive are your employees to changes brought about by AI?',
388
+ options=["High receptiveness", "Moderate receptiveness", "Limited receptiveness", "Not receptive", "Unsure"],
389
+ scores=[5, 4, 3, 1, 0],
390
+ max_score=5
391
+ ),
392
+ ]
393
+ db.session.bulk_save_objects(questions)
394
+ db.session.commit()
395
+
396
+
397
+ def calculate_score(assessment):
398
+ responses = Response.query.filter_by(assessment_id=assessment.id).all()
399
+ category_scores = {
400
+ 'Strategy': 0,
401
+ 'Governance': 0,
402
+ 'Data & Infrastructure': 0,
403
+ 'Organization (Talent & Culture)': 0
404
+ }
405
+ category_max_scores = {
406
+ 'Strategy': 19,
407
+ 'Governance': 17,
408
+ 'Data & Infrastructure': 20,
409
+ 'Organization (Talent & Culture)': 17
410
+ }
411
+
412
+ for response in responses:
413
+ question = AssessmentQuestion.query.get(response.question_id)
414
+ if question and question.options:
415
+ option_index = question.options.index(response.answer)
416
+ score = question.scores[option_index]
417
+ category_scores[question.category] += score
418
+
419
+ # Normalize scores to respect maximum categories scores
420
+ for category in category_scores:
421
+ category_scores[category] = min(category_scores[category],
422
+ category_max_scores[category])
423
+
424
+ assessment.strategy_score = category_scores['Strategy']
425
+ assessment.governance_score = category_scores['Governance']
426
+ assessment.data_infrastructure_score = category_scores['Data & Infrastructure']
427
+ assessment.organization_score = category_scores['Organization (Talent & Culture)']
428
+
429
+ total_score = sum(category_scores.values())
430
+ assessment.total_score = total_score
431
+
432
+ if total_score <= 21:
433
+ assessment.readiness_level = 'AI Novice'
434
+ elif total_score <= 43:
435
+ assessment.readiness_level = 'AI Ready'
436
+ elif total_score <= 65:
437
+ assessment.readiness_level = 'AI Proficient'
438
+ else:
439
+ assessment.readiness_level = 'AI Advanced'
440
+
441
+ db.session.commit()
442
+
443
+ @app.route('/static/<path:filename>')
444
+ def serve_static(filename):
445
+ return send_from_directory(app.static_folder, filename)
446
+
447
+ @app.route('/')
448
+ def home():
449
+ return render_template('home.html')
450
+
451
+ @app.route('/register', methods=['GET', 'POST'])
452
+ def register():
453
+ form = RegistrationForm()
454
+ if form.validate_on_submit():
455
+ user = User.query.filter_by(email=form.email.data).first()
456
+ if user:
457
+ flash('Email already registered. Please use a different email.', 'danger')
458
+ return redirect(url_for('register'))
459
+ new_user = User(email=form.email.data)
460
+ new_user.set_password(form.password.data)
461
+ db.session.add(new_user)
462
+ db.session.commit()
463
+ flash('Registration successful. Please log in.', 'success')
464
+ return redirect(url_for('login'))
465
+ return render_template('register.html', form=form)
466
+
467
+ @app.route('/login', methods=['GET', 'POST'])
468
+ def login():
469
+ form = LoginForm()
470
+ if form.validate_on_submit():
471
+ user = User.query.filter_by(email=form.email.data).first()
472
+ if user and user.check_password(form.password.data):
473
+ login_user(user)
474
+ flash('Login successful.', 'success')
475
+ return redirect(url_for('dashboard'))
476
+ else:
477
+ flash('Invalid email or password.', 'danger')
478
+ return render_template('login.html', form=form)
479
+
480
+ @app.route('/logout')
481
+ @login_required
482
+ def logout():
483
+ logout_user()
484
+ flash('You have been logged out.', 'info')
485
+ return redirect(url_for('home'))
486
+
487
+ @app.route('/dashboard')
488
+ @login_required
489
+ def dashboard():
490
+ return render_template('dashboard.html')
491
+
492
+ @app.route('/start_assessment')
493
+ @login_required
494
+ def start_assessment():
495
+ assessment = Assessment(user_id=current_user.id)
496
+ db.session.add(assessment)
497
+ db.session.commit()
498
+ return redirect(url_for('assessment_question', assessment_id=assessment.id))
499
+
500
+ @app.route('/assessment/<int:assessment_id>', methods=['GET', 'POST'])
501
+ @login_required
502
+ def assessment_question(assessment_id):
503
+ assessment = Assessment.query.get_or_404(assessment_id)
504
+ if assessment.user_id != current_user.id:
505
+ flash('Unauthorized access to assessment', 'danger')
506
+ return redirect(url_for('dashboard'))
507
+
508
+ questions = AssessmentQuestion.query.all()
509
+ current_question_index = assessment.current_question - 1
510
+
511
+ if current_question_index >= len(questions):
512
+ return redirect(url_for('assessment_complete', assessment_id=assessment_id))
513
+
514
+ current_questions = questions[current_question_index:current_question_index+4]
515
+
516
+ if request.method == 'POST':
517
+ for question in current_questions:
518
+ answer = request.form.get(f'question_{question.id}')
519
+ if answer:
520
+ response = Response(assessment_id=assessment_id, question_id=question.id, answer=answer)
521
+ db.session.add(response)
522
+ assessment.current_question += len(current_questions)
523
+
524
+ db.session.commit()
525
+ return redirect(url_for('assessment_question', assessment_id=assessment_id))
526
+ return render_template('assessment_questions.html', questions=current_questions, assessment=assessment)
527
+
528
+ @app.route('/assessment/<int:assessment_id>/complete')
529
+ @login_required
530
+ def assessment_complete(assessment_id):
531
+ assessment = Assessment.query.get_or_404(assessment_id)
532
+ if assessment.user_id != current_user.id:
533
+ flash('Unauthorized access to assessment', 'danger')
534
+ return redirect(url_for('dashboard'))
535
+
536
+ calculate_score(assessment)
537
+ assessment.status = 'Complete'
538
+ assessment.completion_date = datetime.now(timezone.utc)
539
+ db.session.commit()
540
+
541
+ return render_template('assessment_complete.html', assessment=assessment, strategy_score=assessment.strategy_score,
542
+ governance_score=assessment.governance_score,
543
+ data_infrastructure_score=assessment.data_infrastructure_score,
544
+ organization_score=assessment.organization_score,
545
+ total_score=assessment.total_score,
546
+ readiness_level=assessment.readiness_level)
547
+
548
+ @app.route('/assessment/<int:assessment_id>/pdf')
549
+ @login_required
550
+ def generate_pdf(assessment_id):
551
+ assessment = Assessment.query.get_or_404(assessment_id)
552
+ if assessment.user_id != current_user.id:
553
+ flash('Unauthorized access to assessment', 'danger')
554
+ return redirect(url_for('dashboard'))
555
+
556
+ pdf_buffer = generate_pdf_report(assessment)
557
+ pdf_buffer.seek(0)
558
+ return send_file(
559
+ io.BytesIO(pdf_buffer.getvalue()),
560
+ mimetype='application/pdf',
561
+ as_attachment=True,
562
+ download_name=f'AI_Readiness_Report_{assessment_id}.pdf' # Changed from attachment_filename
563
+ )
564
+
565
+ with app.app_context():
566
+ db.drop_all()
567
+ db.create_all()
568
+ populate_questions()
569
+
570
+ if __name__ == '__main__':
571
+ with app.app_context():
572
+ db.create_all()
573
+ if not AssessmentQuestion.query.first():
574
+ populate_questions()
575
  app.run(debug=True)